Line data Source code
1 : //=== JSON.cpp - JSON value, parsing and serialization - C++ -----------*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===---------------------------------------------------------------------===//
9 :
10 : #include "llvm/Support/JSON.h"
11 : #include "llvm/Support/ConvertUTF.h"
12 : #include "llvm/Support/Format.h"
13 : #include <cctype>
14 :
15 : namespace llvm {
16 : namespace json {
17 :
18 0 : Value &Object::operator[](const ObjectKey &K) {
19 0 : return try_emplace(K, nullptr).first->getSecond();
20 : }
21 5911 : Value &Object::operator[](ObjectKey &&K) {
22 5911 : return try_emplace(std::move(K), nullptr).first->getSecond();
23 : }
24 421 : Value *Object::get(StringRef K) {
25 421 : auto I = find(K);
26 421 : if (I == end())
27 : return nullptr;
28 272 : return &I->second;
29 : }
30 6053 : const Value *Object::get(StringRef K) const {
31 6053 : auto I = find(K);
32 6053 : if (I == end())
33 : return nullptr;
34 5716 : return &I->second;
35 : }
36 3 : llvm::Optional<std::nullptr_t> Object::getNull(StringRef K) const {
37 3 : if (auto *V = get(K))
38 2 : return V->getAsNull();
39 : return llvm::None;
40 : }
41 6 : llvm::Optional<bool> Object::getBoolean(StringRef K) const {
42 6 : if (auto *V = get(K))
43 : return V->getAsBoolean();
44 : return llvm::None;
45 : }
46 1 : llvm::Optional<double> Object::getNumber(StringRef K) const {
47 1 : if (auto *V = get(K))
48 : return V->getAsNumber();
49 : return llvm::None;
50 : }
51 1 : llvm::Optional<int64_t> Object::getInteger(StringRef K) const {
52 1 : if (auto *V = get(K))
53 1 : return V->getAsInteger();
54 : return llvm::None;
55 : }
56 1722 : llvm::Optional<llvm::StringRef> Object::getString(StringRef K) const {
57 1722 : if (auto *V = get(K))
58 : return V->getAsString();
59 : return llvm::None;
60 : }
61 98 : const json::Object *Object::getObject(StringRef K) const {
62 98 : if (auto *V = get(K))
63 : return V->getAsObject();
64 : return nullptr;
65 : }
66 4 : json::Object *Object::getObject(StringRef K) {
67 4 : if (auto *V = get(K))
68 : return V->getAsObject();
69 : return nullptr;
70 : }
71 1058 : const json::Array *Object::getArray(StringRef K) const {
72 1058 : if (auto *V = get(K))
73 : return V->getAsArray();
74 : return nullptr;
75 : }
76 1 : json::Array *Object::getArray(StringRef K) {
77 1 : if (auto *V = get(K))
78 : return V->getAsArray();
79 : return nullptr;
80 : }
81 6 : bool operator==(const Object &LHS, const Object &RHS) {
82 6 : if (LHS.size() != RHS.size())
83 : return false;
84 12 : for (const auto &L : LHS) {
85 6 : auto R = RHS.find(L.first);
86 6 : if (R == RHS.end() || L.second != R->second)
87 : return false;
88 : }
89 6 : return true;
90 : }
91 :
92 518 : Array::Array(std::initializer_list<Value> Elements) {
93 518 : V.reserve(Elements.size());
94 2940 : for (const Value &V : Elements) {
95 2422 : emplace_back(nullptr);
96 2422 : back().moveFrom(std::move(V));
97 : }
98 518 : }
99 :
100 175 : Value::Value(std::initializer_list<Value> Elements)
101 175 : : Value(json::Array(Elements)) {}
102 :
103 10886 : void Value::copyFrom(const Value &M) {
104 10886 : Type = M.Type;
105 10886 : switch (Type) {
106 5537 : case T_Null:
107 : case T_Boolean:
108 : case T_Double:
109 : case T_Integer:
110 5537 : memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
111 5537 : break;
112 : case T_StringRef:
113 : create<StringRef>(M.as<StringRef>());
114 14 : break;
115 : case T_String:
116 : create<std::string>(M.as<std::string>());
117 : break;
118 : case T_Object:
119 : create<json::Object>(M.as<json::Object>());
120 : break;
121 : case T_Array:
122 1109 : create<json::Array>(M.as<json::Array>());
123 1109 : break;
124 : }
125 10886 : }
126 :
127 16759 : void Value::moveFrom(const Value &&M) {
128 16759 : Type = M.Type;
129 16759 : switch (Type) {
130 5534 : case T_Null:
131 : case T_Boolean:
132 : case T_Double:
133 : case T_Integer:
134 5534 : memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
135 5534 : break;
136 : case T_StringRef:
137 : create<StringRef>(M.as<StringRef>());
138 585 : break;
139 : case T_String:
140 : create<std::string>(std::move(M.as<std::string>()));
141 4471 : M.Type = T_Null;
142 4471 : break;
143 : case T_Object:
144 : create<json::Object>(std::move(M.as<json::Object>()));
145 4541 : M.Type = T_Null;
146 4541 : break;
147 : case T_Array:
148 : create<json::Array>(std::move(M.as<json::Array>()));
149 1628 : M.Type = T_Null;
150 1628 : break;
151 : }
152 16759 : }
153 :
154 49921 : void Value::destroy() {
155 49921 : switch (Type) {
156 : case T_Null:
157 : case T_Boolean:
158 : case T_Double:
159 : case T_Integer:
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 2693 : as<json::Array>().~Array();
172 2693 : break;
173 : }
174 49921 : }
175 :
176 35 : bool operator==(const Value &L, const Value &R) {
177 35 : if (L.kind() != R.kind())
178 : return false;
179 35 : switch (L.kind()) {
180 : case Value::Null:
181 : return *L.getAsNull() == *R.getAsNull();
182 : case Value::Boolean:
183 4 : return *L.getAsBoolean() == *R.getAsBoolean();
184 : case Value::Number:
185 13 : return *L.getAsNumber() == *R.getAsNumber();
186 : case Value::String:
187 8 : return *L.getAsString() == *R.getAsString();
188 : case Value::Array:
189 6 : return *L.getAsArray() == *R.getAsArray();
190 : case Value::Object:
191 5 : return *L.getAsObject() == *R.getAsObject();
192 : }
193 0 : llvm_unreachable("Unknown value kind");
194 : }
195 :
196 : namespace {
197 : // Simple recursive-descent JSON parser.
198 : class Parser {
199 : public:
200 : Parser(StringRef JSON)
201 888 : : Start(JSON.begin()), P(JSON.begin()), End(JSON.end()) {}
202 :
203 444 : bool checkUTF8() {
204 : size_t ErrOffset;
205 888 : if (isUTF8(StringRef(Start, End - Start), &ErrOffset))
206 : return true;
207 1 : P = Start + ErrOffset; // For line/column calculation.
208 1 : return parseError("Invalid UTF-8 sequence");
209 : }
210 :
211 : bool parseValue(Value &Out);
212 :
213 427 : bool assertEnd() {
214 427 : eatWhitespace();
215 427 : if (P == End)
216 : return true;
217 1 : return parseError("Text after end of document");
218 : }
219 :
220 : Error takeError() {
221 : assert(Err);
222 : return std::move(*Err);
223 : }
224 :
225 : private:
226 0 : void eatWhitespace() {
227 111028 : while (P != End && (*P == ' ' || *P == '\r' || *P == '\n' || *P == '\t'))
228 78979 : ++P;
229 0 : }
230 :
231 : // On invalid syntax, parseX() functions return false and set Err.
232 : bool parseNumber(char First, Value &Out);
233 : bool parseString(std::string &Out);
234 : bool parseUnicode(std::string &Out);
235 : bool parseError(const char *Msg); // always returns false
236 :
237 21870 : char next() { return P == End ? 0 : *P++; }
238 3531 : char peek() { return P == End ? 0 : *P; }
239 : static bool isNumber(char C) {
240 : return C == '0' || C == '1' || C == '2' || C == '3' || C == '4' ||
241 2252 : C == '5' || C == '6' || C == '7' || C == '8' || C == '9' ||
242 704 : C == 'e' || C == 'E' || C == '+' || C == '-' || C == '.';
243 : }
244 :
245 : Optional<Error> Err;
246 : const char *Start, *P, *End;
247 : };
248 :
249 7269 : bool Parser::parseValue(Value &Out) {
250 7269 : eatWhitespace();
251 7269 : if (P == End)
252 2 : return parseError("Unexpected EOF");
253 7267 : switch (char C = next()) {
254 : // Bare null/true/false are easy - first char identifies them.
255 : case 'n':
256 3 : Out = nullptr;
257 9 : return (next() == 'u' && next() == 'l' && next() == 'l') ||
258 0 : parseError("Invalid JSON value (null?)");
259 : case 't':
260 14 : Out = true;
261 42 : return (next() == 'r' && next() == 'u' && next() == 'e') ||
262 0 : parseError("Invalid JSON value (true?)");
263 : case 'f':
264 3 : Out = false;
265 10 : return (next() == 'a' && next() == 'l' && next() == 's' && next() == 'e') ||
266 1 : parseError("Invalid JSON value (false?)");
267 : case '"': {
268 : std::string S;
269 3984 : if (parseString(S)) {
270 7960 : Out = std::move(S);
271 3980 : return true;
272 : }
273 : return false;
274 : }
275 827 : case '[': {
276 827 : Out = Array{};
277 : Array &A = *Out.getAsArray();
278 827 : eatWhitespace();
279 826 : if (peek() == ']') {
280 4 : ++P;
281 4 : return true;
282 : }
283 : for (;;) {
284 1499 : A.emplace_back(nullptr);
285 1499 : if (!parseValue(A.back()))
286 : return false;
287 1497 : eatWhitespace();
288 1497 : switch (next()) {
289 : case ',':
290 : eatWhitespace();
291 : continue;
292 : case ']':
293 : return true;
294 1 : default:
295 1 : return parseError("Expected , or ] after array element");
296 : }
297 : }
298 : }
299 2012 : case '{': {
300 4024 : Out = Object{};
301 : Object &O = *Out.getAsObject();
302 2012 : eatWhitespace();
303 2012 : if (peek() == '}') {
304 37 : ++P;
305 37 : return true;
306 : }
307 : for (;;) {
308 5332 : if (next() != '"')
309 1975 : return parseError("Expected object key");
310 : std::string K;
311 5330 : if (!parseString(K))
312 : return false;
313 5330 : eatWhitespace();
314 5328 : if (next() != ':')
315 3 : return parseError("Expected : after object key");
316 : eatWhitespace();
317 10654 : if (!parseValue(O[std::move(K)]))
318 : return false;
319 5327 : eatWhitespace();
320 5327 : switch (next()) {
321 : case ',':
322 : eatWhitespace();
323 : continue;
324 : case '}':
325 : return true;
326 1 : default:
327 1 : return parseError("Expected , or } after object property");
328 : }
329 : }
330 : }
331 424 : default:
332 424 : if (isNumber(C))
333 423 : return parseNumber(C, Out);
334 1 : return parseError("Invalid JSON value");
335 : }
336 : }
337 :
338 423 : bool Parser::parseNumber(char First, Value &Out) {
339 : // Read the number into a string. (Must be null-terminated for strto*).
340 : SmallString<24> S;
341 423 : S.push_back(First);
342 702 : while (isNumber(peek()))
343 279 : S.push_back(next());
344 : char *End;
345 : // Try first to parse as integer, and if so preserve full 64 bits.
346 : // strtoll returns long long >= 64 bits, so check it's in range too.
347 423 : auto I = std::strtoll(S.c_str(), &End, 10);
348 423 : if (End == S.end() && I >= std::numeric_limits<int64_t>::min() &&
349 : I <= std::numeric_limits<int64_t>::max()) {
350 414 : Out = int64_t(I);
351 414 : return true;
352 : }
353 : // If it's not an integer
354 18 : Out = std::strtod(S.c_str(), &End);
355 9 : return End == S.end() || parseError("Invalid JSON value (number?)");
356 : }
357 :
358 9314 : bool Parser::parseString(std::string &Out) {
359 : // leading quote was already consumed.
360 138791 : for (char C = next(); C != '"'; C = next()) {
361 120167 : if (LLVM_UNLIKELY(P == End))
362 1 : return parseError("Unterminated string");
363 120166 : if (LLVM_UNLIKELY((C & 0x1f) == C))
364 1 : return parseError("Control character in string");
365 120165 : if (LLVM_LIKELY(C != '\\')) {
366 120082 : Out.push_back(C);
367 120082 : continue;
368 : }
369 : // Handle escape sequence.
370 83 : switch (C = next()) {
371 9 : case '"':
372 : case '\\':
373 : case '/':
374 9 : Out.push_back(C);
375 9 : break;
376 1 : case 'b':
377 1 : Out.push_back('\b');
378 1 : break;
379 1 : case 'f':
380 1 : Out.push_back('\f');
381 1 : break;
382 62 : case 'n':
383 62 : Out.push_back('\n');
384 62 : break;
385 1 : case 'r':
386 1 : Out.push_back('\r');
387 1 : break;
388 1 : case 't':
389 1 : Out.push_back('\t');
390 1 : break;
391 7 : case 'u':
392 7 : if (!parseUnicode(Out))
393 : return false;
394 : break;
395 1 : default:
396 1 : return parseError("Invalid escape sequence");
397 : }
398 : }
399 : return true;
400 : }
401 :
402 4 : static void encodeUtf8(uint32_t Rune, std::string &Out) {
403 4 : if (Rune < 0x80) {
404 2 : Out.push_back(Rune & 0x7F);
405 2 : } else if (Rune < 0x800) {
406 0 : uint8_t FirstByte = 0xC0 | ((Rune & 0x7C0) >> 6);
407 0 : uint8_t SecondByte = 0x80 | (Rune & 0x3F);
408 0 : Out.push_back(FirstByte);
409 0 : Out.push_back(SecondByte);
410 2 : } else if (Rune < 0x10000) {
411 0 : uint8_t FirstByte = 0xE0 | ((Rune & 0xF000) >> 12);
412 0 : uint8_t SecondByte = 0x80 | ((Rune & 0xFC0) >> 6);
413 0 : uint8_t ThirdByte = 0x80 | (Rune & 0x3F);
414 0 : Out.push_back(FirstByte);
415 0 : Out.push_back(SecondByte);
416 0 : Out.push_back(ThirdByte);
417 2 : } else if (Rune < 0x110000) {
418 2 : uint8_t FirstByte = 0xF0 | ((Rune & 0x1F0000) >> 18);
419 2 : uint8_t SecondByte = 0x80 | ((Rune & 0x3F000) >> 12);
420 2 : uint8_t ThirdByte = 0x80 | ((Rune & 0xFC0) >> 6);
421 2 : uint8_t FourthByte = 0x80 | (Rune & 0x3F);
422 2 : Out.push_back(FirstByte);
423 2 : Out.push_back(SecondByte);
424 2 : Out.push_back(ThirdByte);
425 2 : Out.push_back(FourthByte);
426 : } else {
427 0 : llvm_unreachable("Invalid codepoint");
428 : }
429 4 : }
430 :
431 : // Parse a UTF-16 \uNNNN escape sequence. "\u" has already been consumed.
432 : // May parse several sequential escapes to ensure proper surrogate handling.
433 : // We do not use ConvertUTF.h, it can't accept and replace unpaired surrogates.
434 : // These are invalid Unicode but valid JSON (RFC 8259, section 8.2).
435 7 : bool Parser::parseUnicode(std::string &Out) {
436 : // Invalid UTF is not a JSON error (RFC 8529ยง8.2). It gets replaced by U+FFFD.
437 : auto Invalid = [&] { Out.append(/* UTF-8 */ {'\xef', '\xbf', '\xbd'}); };
438 : // Decodes 4 hex digits from the stream into Out, returns false on error.
439 : auto Parse4Hex = [this](uint16_t &Out) -> bool {
440 : Out = 0;
441 : char Bytes[] = {next(), next(), next(), next()};
442 : for (unsigned char C : Bytes) {
443 : if (!std::isxdigit(C))
444 : return parseError("Invalid \\u escape sequence");
445 : Out <<= 4;
446 : Out |= (C > '9') ? (C & ~0x20) - 'A' + 10 : (C - '0');
447 : }
448 : return true;
449 : };
450 : uint16_t First; // UTF-16 code unit from the first \u escape.
451 7 : if (!Parse4Hex(First))
452 : return false;
453 :
454 : // We loop to allow proper surrogate-pair error handling.
455 : while (true) {
456 : // Case 1: the UTF-16 code unit is already a codepoint in the BMP.
457 7 : if (LLVM_LIKELY(First < 0xD800 || First >= 0xE000)) {
458 2 : encodeUtf8(First, Out);
459 6 : return true;
460 : }
461 :
462 : // Case 2: it's an (unpaired) trailing surrogate.
463 5 : if (LLVM_UNLIKELY(First >= 0xDC00)) {
464 : Invalid();
465 1 : return true;
466 : }
467 :
468 : // Case 3: it's a leading surrogate. We expect a trailing one next.
469 : // Case 3a: there's no trailing \u escape. Don't advance in the stream.
470 4 : if (LLVM_UNLIKELY(P + 2 > End || *P != '\\' || *(P + 1) != 'u')) {
471 : Invalid(); // Leading surrogate was unpaired.
472 1 : return true;
473 : }
474 3 : P += 2;
475 : uint16_t Second;
476 3 : if (!Parse4Hex(Second))
477 : return false;
478 : // Case 3b: there was another \u escape, but it wasn't a trailing surrogate.
479 3 : if (LLVM_UNLIKELY(Second < 0xDC00 || Second >= 0xE000)) {
480 : Invalid(); // Leading surrogate was unpaired.
481 1 : First = Second; // Second escape still needs to be processed.
482 1 : continue;
483 : }
484 : // Case 3c: a valid surrogate pair encoding an astral codepoint.
485 2 : encodeUtf8(0x10000 | ((First - 0xD800) << 10) | (Second - 0xDC00), Out);
486 2 : return true;
487 : }
488 : }
489 :
490 18 : bool Parser::parseError(const char *Msg) {
491 : int Line = 1;
492 18 : const char *StartOfLine = Start;
493 112 : for (const char *X = Start; X < P; ++X) {
494 94 : if (*X == 0x0A) {
495 3 : ++Line;
496 3 : StartOfLine = X + 1;
497 : }
498 : }
499 : Err.emplace(
500 18 : llvm::make_unique<ParseError>(Msg, Line, P - StartOfLine, P - Start));
501 18 : return false;
502 : }
503 : } // namespace
504 :
505 444 : Expected<Value> parse(StringRef JSON) {
506 : Parser P(JSON);
507 : Value E = nullptr;
508 444 : if (P.checkUTF8())
509 443 : if (P.parseValue(E))
510 427 : if (P.assertEnd())
511 : return std::move(E);
512 : return P.takeError();
513 : }
514 : char ParseError::ID = 0;
515 :
516 1285 : static std::vector<const Object::value_type *> sortedElements(const Object &O) {
517 : std::vector<const Object::value_type *> Elements;
518 5114 : for (const auto &E : O)
519 3829 : Elements.push_back(&E);
520 : llvm::sort(Elements,
521 : [](const Object::value_type *L, const Object::value_type *R) {
522 : return L->first < R->first;
523 : });
524 1285 : return Elements;
525 : }
526 :
527 174406 : bool isUTF8(llvm::StringRef S, size_t *ErrOffset) {
528 : // Fast-path for ASCII, which is valid UTF-8.
529 174406 : if (LLVM_LIKELY(isASCII(S)))
530 : return true;
531 :
532 21 : const UTF8 *Data = reinterpret_cast<const UTF8 *>(S.data()), *Rest = Data;
533 21 : if (LLVM_LIKELY(isLegalUTF8String(&Rest, Data + S.size())))
534 : return true;
535 :
536 9 : if (ErrOffset)
537 1 : *ErrOffset = Rest - Data;
538 : return false;
539 : }
540 :
541 11 : std::string fixUTF8(llvm::StringRef S) {
542 : // This isn't particularly efficient, but is only for error-recovery.
543 11 : std::vector<UTF32> Codepoints(S.size()); // 1 codepoint per byte suffices.
544 11 : const UTF8 *In8 = reinterpret_cast<const UTF8 *>(S.data());
545 11 : UTF32 *Out32 = Codepoints.data();
546 11 : ConvertUTF8toUTF32(&In8, In8 + S.size(), &Out32, Out32 + Codepoints.size(),
547 : lenientConversion);
548 11 : Codepoints.resize(Out32 - Codepoints.data());
549 22 : std::string Res(4 * Codepoints.size(), 0); // 4 bytes per codepoint suffice
550 11 : const UTF32 *In32 = Codepoints.data();
551 11 : UTF8 *Out8 = reinterpret_cast<UTF8 *>(&Res[0]);
552 11 : ConvertUTF32toUTF8(&In32, In32 + Codepoints.size(), &Out8, Out8 + Res.size(),
553 : strictConversion);
554 22 : Res.resize(reinterpret_cast<char *>(Out8) - Res.data());
555 11 : return Res;
556 : }
557 :
558 : } // namespace json
559 : } // namespace llvm
560 :
561 4936 : static void quote(llvm::raw_ostream &OS, llvm::StringRef S) {
562 : OS << '\"';
563 52417 : for (unsigned char C : S) {
564 47481 : if (C == 0x22 || C == 0x5C)
565 : OS << '\\';
566 47481 : if (C >= 0x20) {
567 47441 : OS << C;
568 47441 : continue;
569 : }
570 : OS << '\\';
571 40 : switch (C) {
572 : // A few characters are common enough to make short escapes worthwhile.
573 : case '\t':
574 : OS << 't';
575 : break;
576 : case '\n':
577 : OS << 'n';
578 : break;
579 : case '\r':
580 : OS << 'r';
581 : break;
582 : default:
583 : OS << 'u';
584 11 : llvm::write_hex(OS, C, llvm::HexPrintStyle::Lower, 4);
585 11 : break;
586 : }
587 : }
588 : OS << '\"';
589 4936 : }
590 :
591 : enum IndenterAction {
592 : Indent,
593 : Outdent,
594 : Newline,
595 : Space,
596 : };
597 :
598 : // Prints JSON. The indenter can be used to control formatting.
599 : template <typename Indenter>
600 7497 : void llvm::json::Value::print(raw_ostream &OS, const Indenter &I) const {
601 7497 : switch (Type) {
602 80 : case T_Null:
603 80 : OS << "null";
604 80 : break;
605 : case T_Boolean:
606 957 : OS << (as<bool>() ? "true" : "false");
607 785 : break;
608 : case T_Double:
609 318 : OS << format("%.*g", std::numeric_limits<double>::max_digits10,
610 : as<double>());
611 159 : break;
612 : case T_Integer:
613 3323 : OS << as<int64_t>();
614 3323 : break;
615 : case T_StringRef:
616 574 : quote(OS, as<StringRef>());
617 574 : break;
618 : case T_String:
619 533 : quote(OS, as<std::string>());
620 533 : break;
621 1285 : case T_Object: {
622 : bool Comma = false;
623 : OS << '{';
624 : I(Indent);
625 6399 : for (const auto *P : sortedElements(as<json::Object>())) {
626 3829 : if (Comma)
627 : OS << ',';
628 : Comma = true;
629 2911 : I(Newline);
630 3829 : quote(OS, P->first);
631 : OS << ':';
632 2911 : I(Space);
633 3829 : P->second.print(OS, I);
634 : }
635 : I(Outdent);
636 1031 : if (Comma)
637 1023 : I(Newline);
638 : OS << '}';
639 : break;
640 : }
641 758 : case T_Array: {
642 : bool Comma = false;
643 : OS << '[';
644 : I(Indent);
645 3768 : for (const auto &E : as<json::Array>()) {
646 3010 : if (Comma)
647 : OS << ',';
648 : Comma = true;
649 350 : I(Newline);
650 3010 : E.print(OS, I);
651 : }
652 : I(Outdent);
653 249 : if (Comma)
654 189 : I(Newline);
655 : OS << ']';
656 : break;
657 : }
658 : }
659 7497 : }
660 4008 :
661 4008 : void llvm::format_provider<llvm::json::Value>::format(
662 41 : const llvm::json::Value &E, raw_ostream &OS, StringRef Options) {
663 41 : if (Options.empty()) {
664 41 : OS << E;
665 : return;
666 479 : }
667 360 : unsigned IndentAmount = 0;
668 : if (Options.getAsInteger(/*Radix=*/10, IndentAmount))
669 244 : llvm_unreachable("json::Value format options should be an integer");
670 : unsigned IndentLevel = 0;
671 122 : E.print(OS, [&](IndenterAction A) {
672 : switch (A) {
673 2545 : case Newline:
674 2545 : OS << '\n';
675 : OS.indent(IndentLevel);
676 53 : break;
677 53 : case Space:
678 : OS << ' ';
679 124 : break;
680 124 : case Indent:
681 254 : IndentLevel += IndentAmount;
682 : break;
683 : case Outdent:
684 : IndentLevel -= IndentAmount;
685 1426 : break;
686 918 : };
687 : });
688 : }
689 :
690 918 : llvm::raw_ostream &llvm::json::operator<<(raw_ostream &OS, const Value &E) {
691 : E.print(OS, [](IndenterAction A) { /*ignore*/ });
692 : return OS;
693 918 : }
|