llvm.org GIT mirror llvm / 5070d36
Lift JSON library from clang-tools-extra/clangd to llvm/Support. Summary: This consists of four main parts: - an type json::Expr representing JSON values of dynamic kind, which can be composed, inspected, and modified - a JSON parser from string -> json::Expr - a JSON printer from json::Expr -> string, with optional pretty-printing - a convention for mapping json::Expr <=> native types (fromJSON/toJSON) Mapping functions are provided for primitives (e.g. int, vector) and the ObjectMapper helper helps implement fromJSON for struct/object types. Based on clangd's usage, a couple of places I'd appreciate review attention: - fromJSON returns only bool. A richer error-signaling mechanism may be useful to provide useful messages, or let recursive fromJSONs (containers/structs) do careful error recovery. - should json::obj be always explicitly written (like json::ary) - there's no streaming parse API. I suspect there are some simple wins like a callback API where the document is a long array, and each element is small. But this can probably be bolted on easily when we see the need. Reviewers: bkramer, labath Subscribers: mgorny, ilya-biryukov, ioeric, MaskRay, llvm-commits Differential Revision: https://reviews.llvm.org/D45753 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@336534 91177308-0d34-0410-b5e6-96231b3b80d8 Sam McCall 1 year, 3 months ago
5 changed file(s) with 1563 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===--- JSON.h - JSON values, parsing and serialization -------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===---------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file supports working with JSON data.
11 ///
12 /// It comprises:
13 ///
14 /// - classes which hold dynamically-typed parsed JSON structures
15 /// These are value types that can be composed, inspected, and modified.
16 /// See json::Value, and the related types json::Object and json::Array.
17 ///
18 /// - functions to parse JSON text into Values, and to serialize Values to text.
19 /// See parse(), operator<<, and format_provider.
20 ///
21 /// - a convention and helpers for mapping between json::Value and user-defined
22 /// types. See fromJSON(), ObjectMapper, and the class comment on Value.
23 ///
24 /// Typically, JSON data would be read from an external source, parsed into
25 /// a Value, and then converted into some native data structure before doing
26 /// real work on it. (And vice versa when writing).
27 ///
28 /// Other serialization mechanisms you may consider:
29 ///
30 /// - YAML is also text-based, and more human-readable than JSON. It's a more
31 /// complex format and data model, and YAML parsers aren't ubiquitous.
32 /// YAMLParser.h is a streaming parser suitable for parsing large documents
33 /// (including JSON, as YAML is a superset). It can be awkward to use
34 /// directly. YAML I/O (YAMLTraits.h) provides data mapping that is more
35 /// declarative than the toJSON/fromJSON conventions here.
36 ///
37 /// - LLVM bitstream is a space- and CPU- efficient binary format. Typically it
38 /// encodes LLVM IR ("bitcode"), but it can be a container for other data.
39 /// Low-level reader/writer libraries are in Bitcode/Bitstream*.h
40 ///
41 //===---------------------------------------------------------------------===//
42
43 #ifndef LLVM_SUPPORT_JSON_H
44 #define LLVM_SUPPORT_JSON_H
45
46 #include "llvm/ADT/DenseMap.h"
47 #include "llvm/ADT/SmallVector.h"
48 #include "llvm/ADT/StringRef.h"
49 #include "llvm/Support/Error.h"
50 #include "llvm/Support/FormatVariadic.h"
51 #include "llvm/Support/raw_ostream.h"
52 #include
53
54 namespace llvm {
55 namespace json {
56 class Array;
57 class ObjectKey;
58 class Value;
59
60 /// An Object is a JSON object, which maps strings to heterogenous JSON values.
61 /// It simulates DenseMap. ObjectKey is a maybe-owned string.
62 class Object {
63 using Storage = DenseMap>;
64 Storage M;
65
66 public:
67 using key_type = ObjectKey;
68 using mapped_type = Value;
69 using value_type = Storage::value_type;
70 using iterator = Storage::iterator;
71 using const_iterator = Storage::const_iterator;
72
73 explicit Object() = default;
74 // KV is a trivial key-value struct for list-initialization.
75 // (using std::pair forces extra copies).
76 struct KV;
77 explicit Object(std::initializer_list Properties);
78
79 iterator begin() { return M.begin(); }
80 const_iterator begin() const { return M.begin(); }
81 iterator end() { return M.end(); }
82 const_iterator end() const { return M.end(); }
83
84 bool empty() const { return M.empty(); }
85 size_t size() const { return M.size(); }
86
87 void clear() { M.clear(); }
88 std::pair insert(KV E);
89 template
90 std::pair try_emplace(const ObjectKey &K, Ts &&... Args) {
91 return M.try_emplace(K, std::forward(Args)...);
92 }
93 template
94 std::pair try_emplace(ObjectKey &&K, Ts &&... Args) {
95 return M.try_emplace(std::move(K), std::forward(Args)...);
96 }
97
98 iterator find(StringRef K) { return M.find_as(K); }
99 const_iterator find(StringRef K) const { return M.find_as(K); }
100 // operator[] acts as if Value was default-constructible as null.
101 Value &operator[](const ObjectKey &K);
102 Value &operator[](ObjectKey &&K);
103 // Look up a property, returning nullptr if it doesn't exist.
104 Value *get(StringRef K);
105 const Value *get(StringRef K) const;
106 // Typed accessors return None/nullptr if
107 // - the property doesn't exist
108 // - or it has the wrong type
109 llvm::Optional getNull(StringRef K) const;
110 llvm::Optional getBoolean(StringRef K) const;
111 llvm::Optional getNumber(StringRef K) const;
112 llvm::Optional getInteger(StringRef K) const;
113 llvm::Optional getString(StringRef K) const;
114 const json::Object *getObject(StringRef K) const;
115 json::Object *getObject(StringRef K);
116 const json::Array *getArray(StringRef K) const;
117 json::Array *getArray(StringRef K);
118 };
119 bool operator==(const Object &LHS, const Object &RHS);
120 inline bool operator!=(const Object &LHS, const Object &RHS) {
121 return !(LHS == RHS);
122 }
123
124 /// An Array is a JSON array, which contains heterogeneous JSON values.
125 /// It simulates std::vector.
126 class Array {
127 std::vector V;
128
129 public:
130 using value_type = Value;
131 using iterator = std::vector::iterator;
132 using const_iterator = std::vector::const_iterator;
133
134 explicit Array() = default;
135 explicit Array(std::initializer_list Elements);
136 template explicit Array(const Collection &C) {
137 for (const auto &V : C)
138 emplace_back(V);
139 }
140
141 Value &operator[](size_t I) { return V[I]; }
142 const Value &operator[](size_t I) const { return V[I]; }
143 Value &front() { return V.front(); }
144 const Value &front() const { return V.front(); }
145 Value &back() { return V.back(); }
146 const Value &back() const { return V.back(); }
147 Value *data() { return V.data(); }
148 const Value *data() const { return V.data(); }
149
150 iterator begin() { return V.begin(); }
151 const_iterator begin() const { return V.begin(); }
152 iterator end() { return V.end(); }
153 const_iterator end() const { return V.end(); }
154
155 bool empty() const { return V.empty(); }
156 size_t size() const { return V.size(); }
157
158 void clear() { V.clear(); }
159 void push_back(const Value &E) { V.push_back(E); }
160 void push_back(Value &&E) { V.push_back(std::move(E)); }
161 template void emplace_back(Args &&... A) {
162 V.emplace_back(std::forward(A)...);
163 }
164 void pop_back() { V.pop_back(); }
165 iterator insert(const_iterator P, const Value &E) { return V.insert(P, E); }
166 iterator insert(const_iterator P, Value &&E) {
167 return V.insert(P, std::move(E));
168 }
169 template iterator insert(const_iterator P, It A, It Z) {
170 return V.insert(P, A, Z);
171 }
172 template iterator emplace(const_iterator P, Args &&... A) {
173 return V.emplace(P, std::forward(A)...);
174 }
175
176 friend bool operator==(const Array &L, const Array &R) { return L.V == R.V; }
177 };
178 inline bool operator!=(const Array &L, const Array &R) { return !(L == R); }
179
180 /// A Value is an JSON value of unknown type.
181 /// They can be copied, but should generally be moved.
182 ///
183 /// === Composing values ===
184 ///
185 /// You can implicitly construct Values from:
186 /// - strings: std::string, SmallString, formatv, StringRef, char*
187 /// (char*, and StringRef are references, not copies!)
188 /// - numbers
189 /// - booleans
190 /// - null: nullptr
191 /// - arrays: {"foo", 42.0, false}
192 /// - serializable things: types with toJSON(const T&)->Value, found by ADL
193 ///
194 /// They can also be constructed from object/array helpers:
195 /// - json::Object is a type like map
196 /// - json::Array is a type like vector
197 /// These can be list-initialized, or used to build up collections in a loop.
198 /// json::ary(Collection) converts all items in a collection to Values.
199 ///
200 /// === Inspecting values ===
201 ///
202 /// Each Value is one of the JSON kinds:
203 /// null (nullptr_t)
204 /// boolean (bool)
205 /// number (double)
206 /// string (StringRef)
207 /// array (json::Array)
208 /// object (json::Object)
209 ///
210 /// The kind can be queried directly, or implicitly via the typed accessors:
211 /// if (Optional S = E.getAsString()
212 /// assert(E.kind() == Value::String);
213 ///
214 /// Array and Object also have typed indexing accessors for easy traversal:
215 /// Expected E = parse(R"( {"options": {"font": "sans-serif"}} )");
216 /// if (Object* O = E->getAsObject())
217 /// if (Object* Opts = O->getObject("options"))
218 /// if (Optional Font = Opts->getString("font"))
219 /// assert(Opts->at("font").kind() == Value::String);
220 ///
221 /// === Converting JSON values to C++ types ===
222 ///
223 /// The convention is to have a deserializer function findable via ADL:
224 /// fromJSON(const json::Value&, T&)->bool
225 /// Deserializers are provided for:
226 /// - bool
227 /// - int
228 /// - double
229 /// - std::string
230 /// - vector, where T is deserializable
231 /// - map, where T is deserializable
232 /// - Optional, where T is deserializable
233 /// ObjectMapper can help writing fromJSON() functions for object types.
234 ///
235 /// For conversion in the other direction, the serializer function is:
236 /// toJSON(const T&) -> json::Value
237 /// If this exists, then it also allows constructing Value from T, and can
238 /// be used to serialize vector, map, and Optional.
239 ///
240 /// === Serialization ===
241 ///
242 /// Values can be serialized to JSON:
243 /// 1) raw_ostream << Value // Basic formatting.
244 /// 2) raw_ostream << formatv("{0}", Value) // Basic formatting.
245 /// 3) raw_ostream << formatv("{0:2}", Value) // Pretty-print with indent 2.
246 ///
247 /// And parsed:
248 /// Expected E = json::parse("[1, 2, null]");
249 /// assert(E && E->kind() == Value::Array);
250 class Value {
251 public:
252 enum Kind {
253 Null,
254 Boolean,
255 Number,
256 String,
257 Array,
258 Object,
259 };
260
261 // It would be nice to have Value() be null. But that would make {} null too.
262 Value(const Value &M) { copyFrom(M); }
263 Value(Value &&M) { moveFrom(std::move(M)); }
264 Value(std::initializer_list Elements);
265 Value(json::Array &&Elements) : Type(T_Array) {
266 create(std::move(Elements));
267 }
268 Value(json::Object &&Properties) : Type(T_Object) {
269 create(std::move(Properties));
270 }
271 // Strings: types with value semantics.
272 Value(std::string &&V) : Type(T_String) { create(std::move(V)); }
273 Value(const std::string &V) : Type(T_String) { create(V); }
274 Value(const llvm::SmallVectorImpl &V) : Type(T_String) {
275 create(V.begin(), V.end());
276 }
277 Value(const llvm::formatv_object_base &V) : Value(V.str()){};
278 // Strings: types with reference semantics.
279 Value(llvm::StringRef V) : Type(T_StringRef) { create(V); }
280 Value(const char *V) : Type(T_StringRef) { create(V); }
281 Value(std::nullptr_t) : Type(T_Null) {}
282 // Prevent implicit conversions to boolean.
283 template
284 std::is_same::value>::type>
285 Value(T B) : Type(T_Boolean) {
286 create(B);
287 }
288 // Numbers: arithmetic types that are not boolean.
289 template <
290 typename T,
291 typename = typename std::enable_if::value>::type,
292 typename = typename std::enable_if::value>::type>
293 Value(T D) : Type(T_Number) {
294 create(D);
295 }
296 // Serializable types: with a toJSON(const T&)->Value function, found by ADL.
297 template
298 typename = typename std::enable_if
299 Value, decltype(toJSON(*(const T *)nullptr))>::value>>
300 Value(const T &V) : Value(toJSON(V)) {}
301
302 Value &operator=(const Value &M) {
303 destroy();
304 copyFrom(M);
305 return *this;
306 }
307 Value &operator=(Value &&M) {
308 destroy();
309 moveFrom(std::move(M));
310 return *this;
311 }
312 ~Value() { destroy(); }
313
314 Kind kind() const {
315 switch (Type) {
316 case T_Null:
317 return Null;
318 case T_Boolean:
319 return Boolean;
320 case T_Number:
321 return Number;
322 case T_String:
323 case T_StringRef:
324 return String;
325 case T_Object:
326 return Object;
327 case T_Array:
328 return Array;
329 }
330 llvm_unreachable("Unknown kind");
331 }
332
333 // Typed accessors return None/nullptr if the Value is not of this type.
334 llvm::Optional getAsNull() const {
335 if (LLVM_LIKELY(Type == T_Null))
336 return nullptr;
337 return llvm::None;
338 }
339 llvm::Optional getAsBoolean() const {
340 if (LLVM_LIKELY(Type == T_Boolean))
341 return as();
342 return llvm::None;
343 }
344 llvm::Optional getAsNumber() const {
345 if (LLVM_LIKELY(Type == T_Number))
346 return as();
347 return llvm::None;
348 }
349 llvm::Optional getAsInteger() const {
350 if (LLVM_LIKELY(Type == T_Number)) {
351 double D = as();
352 if (LLVM_LIKELY(std::modf(D, &D) == 0.0 &&
353 D >= double(std::numeric_limits::min()) &&
354 D <= double(std::numeric_limits::max())))
355 return D;
356 }
357 return llvm::None;
358 }
359 llvm::Optional getAsString() const {
360 if (Type == T_String)
361 return llvm::StringRef(as());
362 if (LLVM_LIKELY(Type == T_StringRef))
363 return as();
364 return llvm::None;
365 }
366 const json::Object *getAsObject() const {
367 return LLVM_LIKELY(Type == T_Object) ? &as() : nullptr;
368 }
369 json::Object *getAsObject() {
370 return LLVM_LIKELY(Type == T_Object) ? &as() : nullptr;
371 }
372 const json::Array *getAsArray() const {
373 return LLVM_LIKELY(Type == T_Array) ? &as() : nullptr;
374 }
375 json::Array *getAsArray() {
376 return LLVM_LIKELY(Type == T_Array) ? &as() : nullptr;
377 }
378
379 /// Serializes this Value to JSON, writing it to the provided stream.
380 /// The formatting is compact (no extra whitespace) and deterministic.
381 /// For pretty-printing, use the formatv() format_provider below.
382 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Value &);
383
384 private:
385 void destroy();
386 void copyFrom(const Value &M);
387 // We allow moving from *const* Values, by marking all members as mutable!
388 // This hack is needed to support initializer-list syntax efficiently.
389 // (std::initializer_list is a container of const T).
390 void moveFrom(const Value &&M);
391 friend class Array;
392 friend class Object;
393
394 template void create(U &&... V) {
395 new (reinterpret_cast(Union.buffer)) T(std::forward(V)...);
396 }
397 template T &as() const {
398 return *reinterpret_cast(Union.buffer);
399 }
400
401 template
402 void print(llvm::raw_ostream &, const Indenter &) const;
403 friend struct llvm::format_provider;
404
405 enum ValueType : char {
406 T_Null,
407 T_Boolean,
408 // FIXME: splitting Number into Double and Integer would allow us to
409 // round-trip 64-bit integers.
410 T_Number,
411 T_StringRef,
412 T_String,
413 T_Object,
414 T_Array,
415 };
416 // All members mutable, see moveFrom().
417 mutable ValueType Type;
418 mutable llvm::AlignedCharArrayUnion
419 std::string, json::Array, json::Object>
420 Union;
421 };
422
423 bool operator==(const Value &, const Value &);
424 inline bool operator!=(const Value &L, const Value &R) { return !(L == R); }
425 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Value &);
426
427 /// ObjectKey is a used to capture keys in Object. Like Value but:
428 /// - only strings are allowed
429 /// - it's optimized for the string literal case (Owned == nullptr)
430 class ObjectKey {
431 public:
432 ObjectKey(const char *S) : Data(S) {}
433 ObjectKey(llvm::StringRef S) : Data(S) {}
434 ObjectKey(std::string &&V)
435 : Owned(new std::string(std::move(V))), Data(*Owned) {}
436 ObjectKey(const std::string &V) : Owned(new std::string(V)), Data(*Owned) {}
437 ObjectKey(const llvm::SmallVectorImpl &V)
438 : ObjectKey(std::string(V.begin(), V.end())) {}
439 ObjectKey(const llvm::formatv_object_base &V) : ObjectKey(V.str()) {}
440
441 ObjectKey(const ObjectKey &C) { *this = C; }
442 ObjectKey(ObjectKey &&C) : ObjectKey(static_cast(C)) {}
443 ObjectKey &operator=(const ObjectKey &C) {
444 if (C.Owned) {
445 Owned.reset(new std::string(*C.Owned));
446 Data = *Owned;
447 } else {
448 Data = C.Data;
449 }
450 return *this;
451 }
452 ObjectKey &operator=(ObjectKey &&) = default;
453
454 operator llvm::StringRef() const { return Data; }
455 std::string str() const { return Data.str(); }
456
457 private:
458 // FIXME: this is unneccesarily large (3 pointers). Pointer + length + owned
459 // could be 2 pointers at most.
460 std::unique_ptr Owned;
461 llvm::StringRef Data;
462 };
463
464 inline bool operator==(const ObjectKey &L, const ObjectKey &R) {
465 return llvm::StringRef(L) == llvm::StringRef(R);
466 }
467 inline bool operator!=(const ObjectKey &L, const ObjectKey &R) {
468 return !(L == R);
469 }
470 inline bool operator<(const ObjectKey &L, const ObjectKey &R) {
471 return StringRef(L) < StringRef(R);
472 }
473
474 struct Object::KV {
475 ObjectKey K;
476 Value V;
477 };
478
479 inline Object::Object(std::initializer_list Properties) {
480 for (const auto &P : Properties) {
481 auto R = try_emplace(P.K, nullptr);
482 if (R.second)
483 R.first->getSecond().moveFrom(std::move(P.V));
484 }
485 }
486 inline std::pair Object::insert(KV E) {
487 return try_emplace(std::move(E.K), std::move(E.V));
488 }
489
490 // Standard deserializers are provided for primitive types.
491 // See comments on Value.
492 inline bool fromJSON(const Value &E, std::string &Out) {
493 if (auto S = E.getAsString()) {
494 Out = *S;
495 return true;
496 }
497 return false;
498 }
499 inline bool fromJSON(const Value &E, int &Out) {
500 if (auto S = E.getAsInteger()) {
501 Out = *S;
502 return true;
503 }
504 return false;
505 }
506 inline bool fromJSON(const Value &E, double &Out) {
507 if (auto S = E.getAsNumber()) {
508 Out = *S;
509 return true;
510 }
511 return false;
512 }
513 inline bool fromJSON(const Value &E, bool &Out) {
514 if (auto S = E.getAsBoolean()) {
515 Out = *S;
516 return true;
517 }
518 return false;
519 }
520 template bool fromJSON(const Value &E, llvm::Optional &Out) {
521 if (E.getAsNull()) {
522 Out = llvm::None;
523 return true;
524 }
525 T Result;
526 if (!fromJSON(E, Result))
527 return false;
528 Out = std::move(Result);
529 return true;
530 }
531 template bool fromJSON(const Value &E, std::vector &Out) {
532 if (auto *A = E.getAsArray()) {
533 Out.clear();
534 Out.resize(A->size());
535 for (size_t I = 0; I < A->size(); ++I)
536 if (!fromJSON((*A)[I], Out[I]))
537 return false;
538 return true;
539 }
540 return false;
541 }
542 template
543 bool fromJSON(const Value &E, std::map &Out) {
544 if (auto *O = E.getAsObject()) {
545 Out.clear();
546 for (const auto &KV : *O)
547 if (!fromJSON(KV.second, Out[llvm::StringRef(KV.first)]))
548 return false;
549 return true;
550 }
551 return false;
552 }
553
554 /// Helper for mapping JSON objects onto protocol structs.
555 ///
556 /// Example:
557 /// \code
558 /// bool fromJSON(const Value &E, MyStruct &R) {
559 /// ObjectMapper O(E);
560 /// if (!O || !O.map("mandatory_field", R.MandatoryField))
561 /// return false;
562 /// O.map("optional_field", R.OptionalField);
563 /// return true;
564 /// }
565 /// \endcode
566 class ObjectMapper {
567 public:
568 ObjectMapper(const Value &E) : O(E.getAsObject()) {}
569
570 /// True if the expression is an object.
571 /// Must be checked before calling map().
572 operator bool() { return O; }
573
574 /// Maps a property to a field, if it exists.
575 template bool map(StringRef Prop, T &Out) {
576 assert(*this && "Must check this is an object before calling map()");
577 if (const Value *E = O->get(Prop))
578 return fromJSON(*E, Out);
579 return false;
580 }
581
582 /// Maps a property to a field, if it exists.
583 /// (Optional requires special handling, because missing keys are OK).
584 template bool map(StringRef Prop, llvm::Optional &Out) {
585 assert(*this && "Must check this is an object before calling map()");
586 if (const Value *E = O->get(Prop))
587 return fromJSON(*E, Out);
588 Out = llvm::None;
589 return true;
590 }
591
592 private:
593 const Object *O;
594 };
595
596 /// Parses the provided JSON source, or returns a ParseError.
597 /// The returned Value is self-contained and owns its strings (they do not refer
598 /// to the original source).
599 llvm::Expected parse(llvm::StringRef JSON);
600
601 class ParseError : public llvm::ErrorInfo {
602 const char *Msg;
603 unsigned Line, Column, Offset;
604
605 public:
606 static char ID;
607 ParseError(const char *Msg, unsigned Line, unsigned Column, unsigned Offset)
608 : Msg(Msg), Line(Line), Column(Column), Offset(Offset) {}
609 void log(llvm::raw_ostream &OS) const override {
610 OS << llvm::formatv("[{0}:{1}, byte={2}]: {3}", Line, Column, Offset, Msg);
611 }
612 std::error_code convertToErrorCode() const override {
613 return llvm::inconvertibleErrorCode();
614 }
615 };
616 } // namespace json
617
618 /// Allow printing json::Value with formatv().
619 /// The default style is basic/compact formatting, like operator<<.
620 /// A format string like formatv("{0:2}", Value) pretty-prints with indent 2.
621 template <> struct format_provider {
622 static void format(const llvm::json::Value &, raw_ostream &, StringRef);
623 };
624 } // namespace llvm
625
626 #endif
8282 IntEqClasses.cpp
8383 IntervalMap.cpp
8484 JamCRC.cpp
85 JSON.cpp
8586 KnownBits.cpp
8687 LEB128.cpp
8788 LineIterator.cpp
0 //=== JSON.cpp - JSON value, parsing and serialization - C++ -----------*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===---------------------------------------------------------------------===//
8
9 #include "llvm/Support/JSON.h"
10 #include "llvm/Support/Format.h"
11 #include
12
13 namespace llvm {
14 namespace json {
15
16 Value &Object::operator[](const ObjectKey &K) {
17 return try_emplace(K, nullptr).first->getSecond();
18 }
19 Value &Object::operator[](ObjectKey &&K) {
20 return try_emplace(std::move(K), nullptr).first->getSecond();
21 }
22 Value *Object::get(StringRef K) {
23 auto I = find(K);
24 if (I == end())
25 return nullptr;
26 return &I->second;
27 }
28 const Value *Object::get(StringRef K) const {
29 auto I = find(K);
30 if (I == end())
31 return nullptr;
32 return &I->second;
33 }
34 llvm::Optional Object::getNull(StringRef K) const {
35 if (auto *V = get(K))
36 return V->getAsNull();
37 return llvm::None;
38 }
39 llvm::Optional Object::getBoolean(StringRef K) const {
40 if (auto *V = get(K))
41 return V->getAsBoolean();
42 return llvm::None;
43 }
44 llvm::Optional Object::getNumber(StringRef K) const {
45 if (auto *V = get(K))
46 return V->getAsNumber();
47 return llvm::None;
48 }
49 llvm::Optional Object::getInteger(StringRef K) const {
50 if (auto *V = get(K))
51 return V->getAsInteger();
52 return llvm::None;
53 }
54 llvm::Optional Object::getString(StringRef K) const {
55 if (auto *V = get(K))
56 return V->getAsString();
57 return llvm::None;
58 }
59 const json::Object *Object::getObject(StringRef K) const {
60 if (auto *V = get(K))
61 return V->getAsObject();
62 return nullptr;
63 }
64 json::Object *Object::getObject(StringRef K) {
65 if (auto *V = get(K))
66 return V->getAsObject();
67 return nullptr;
68 }
69 const json::Array *Object::getArray(StringRef K) const {
70 if (auto *V = get(K))
71 return V->getAsArray();
72 return nullptr;
73 }
74 json::Array *Object::getArray(StringRef K) {
75 if (auto *V = get(K))
76 return V->getAsArray();
77 return nullptr;
78 }
79 bool operator==(const Object &LHS, const Object &RHS) {
80 if (LHS.size() != RHS.size())
81 return false;
82 for (const auto &L : LHS) {
83 auto R = RHS.find(L.first);
84 if (R == RHS.end() || L.second != R->second)
85 return false;
86 }
87 return true;
88 }
89
90 Array::Array(std::initializer_list Elements) {
91 V.reserve(Elements.size());
92 for (const Value &V : Elements) {
93 emplace_back(nullptr);
94 back().moveFrom(std::move(V));
95 }
96 }
97
98 Value::Value(std::initializer_list Elements)
99 : Value(json::Array(Elements)) {}
100
101 void Value::copyFrom(const Value &M) {
102 Type = M.Type;
103 switch (Type) {
104 case T_Null:
105 case T_Boolean:
106 case T_Number:
107 memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
108 break;
109 case T_StringRef:
110 create(M.as());
111 break;
112 case T_String:
113 create(M.as());
114 break;
115 case T_Object:
116 create(M.as());
117 break;
118 case T_Array:
119 create(M.as());
120 break;
121 }
122 }
123
124 void Value::moveFrom(const Value &&M) {
125 Type = M.Type;
126 switch (Type) {
127 case T_Null:
128 case T_Boolean:
129 case T_Number:
130 memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
131 break;
132 case T_StringRef:
133 create(M.as());
134 break;
135 case T_String:
136 create(std::move(M.as()));
137 M.Type = T_Null;
138 break;
139 case T_Object:
140 create(std::move(M.as()));
141 M.Type = T_Null;
142 break;
143 case T_Array:
144 create(std::move(M.as()));
145 M.Type = T_Null;
146 break;
147 }
148 }
149
150 void Value::destroy() {
151 switch (Type) {
152 case T_Null:
153 case T_Boolean:
154 case T_Number:
155 break;
156 case T_StringRef:
157 as().~StringRef();
158 break;
159 case T_String:
160 as().~basic_string();
161 break;
162 case T_Object:
163 as().~Object();
164 break;
165 case T_Array:
166 as().~Array();
167 break;
168 }
169 }
170
171 bool operator==(const Value &L, const Value &R) {
172 if (L.kind() != R.kind())
173 return false;
174 switch (L.kind()) {
175 case Value::Null:
176 return *L.getAsNull() == *R.getAsNull();
177 case Value::Boolean:
178 return *L.getAsBoolean() == *R.getAsBoolean();
179 case Value::Number:
180 return *L.getAsNumber() == *R.getAsNumber();
181 case Value::String:
182 return *L.getAsString() == *R.getAsString();
183 case Value::Array:
184 return *L.getAsArray() == *R.getAsArray();
185 case Value::Object:
186 return *L.getAsObject() == *R.getAsObject();
187 }
188 llvm_unreachable("Unknown value kind");
189 }
190
191 namespace {
192 // Simple recursive-descent JSON parser.
193 class Parser {
194 public:
195 Parser(StringRef JSON)
196 : Start(JSON.begin()), P(JSON.begin()), End(JSON.end()) {}
197
198 bool parseValue(Value &Out);
199
200 bool assertEnd() {
201 eatWhitespace();
202 if (P == End)
203 return true;
204 return parseError("Text after end of document");
205 }
206
207 Error takeError() {
208 assert(Err);
209 return std::move(*Err);
210 }
211
212 private:
213 void eatWhitespace() {
214 while (P != End && (*P == ' ' || *P == '\r' || *P == '\n' || *P == '\t'))
215 ++P;
216 }
217
218 // On invalid syntax, parseX() functions return false and set Err.
219 bool parseNumber(char First, double &Out);
220 bool parseString(std::string &Out);
221 bool parseUnicode(std::string &Out);
222 bool parseError(const char *Msg); // always returns false
223
224 char next() { return P == End ? 0 : *P++; }
225 char peek() { return P == End ? 0 : *P; }
226 static bool isNumber(char C) {
227 return C == '0' || C == '1' || C == '2' || C == '3' || C == '4' ||
228 C == '5' || C == '6' || C == '7' || C == '8' || C == '9' ||
229 C == 'e' || C == 'E' || C == '+' || C == '-' || C == '.';
230 }
231
232 Optional Err;
233 const char *Start, *P, *End;
234 };
235
236 bool Parser::parseValue(Value &Out) {
237 eatWhitespace();
238 if (P == End)
239 return parseError("Unexpected EOF");
240 switch (char C = next()) {
241 // Bare null/true/false are easy - first char identifies them.
242 case 'n':
243 Out = nullptr;
244 return (next() == 'u' && next() == 'l' && next() == 'l') ||
245 parseError("Invalid JSON value (null?)");
246 case 't':
247 Out = true;
248 return (next() == 'r' && next() == 'u' && next() == 'e') ||
249 parseError("Invalid JSON value (true?)");
250 case 'f':
251 Out = false;
252 return (next() == 'a' && next() == 'l' && next() == 's' && next() == 'e') ||
253 parseError("Invalid JSON value (false?)");
254 case '"': {
255 std::string S;
256 if (parseString(S)) {
257 Out = std::move(S);
258 return true;
259 }
260 return false;
261 }
262 case '[': {
263 Out = Array{};
264 Array &A = *Out.getAsArray();
265 eatWhitespace();
266 if (peek() == ']') {
267 ++P;
268 return true;
269 }
270 for (;;) {
271 A.emplace_back(nullptr);
272 if (!parseValue(A.back()))
273 return false;
274 eatWhitespace();
275 switch (next()) {
276 case ',':
277 eatWhitespace();
278 continue;
279 case ']':
280 return true;
281 default:
282 return parseError("Expected , or ] after array element");
283 }
284 }
285 }
286 case '{': {
287 Out = Object{};
288 Object &O = *Out.getAsObject();
289 eatWhitespace();
290 if (peek() == '}') {
291 ++P;
292 return true;
293 }
294 for (;;) {
295 if (next() != '"')
296 return parseError("Expected object key");
297 std::string K;
298 if (!parseString(K))
299 return false;
300 eatWhitespace();
301 if (next() != ':')
302 return parseError("Expected : after object key");
303 eatWhitespace();
304 if (!parseValue(O[std::move(K)]))
305 return false;
306 eatWhitespace();
307 switch (next()) {
308 case ',':
309 eatWhitespace();
310 continue;
311 case '}':
312 return true;
313 default:
314 return parseError("Expected , or } after object property");
315 }
316 }
317 }
318 default:
319 if (isNumber(C)) {
320 double Num;
321 if (parseNumber(C, Num)) {
322 Out = Num;
323 return true;
324 } else {
325 return false;
326 }
327 }
328 return parseError("Invalid JSON value");
329 }
330 }
331
332 bool Parser::parseNumber(char First, double &Out) {
333 SmallString<24> S;
334 S.push_back(First);
335 while (isNumber(peek()))
336 S.push_back(next());
337 char *End;
338 Out = std::strtod(S.c_str(), &End);
339 return End == S.end() || parseError("Invalid JSON value (number?)");
340 }
341
342 bool Parser::parseString(std::string &Out) {
343 // leading quote was already consumed.
344 for (char C = next(); C != '"'; C = next()) {
345 if (LLVM_UNLIKELY(P == End))
346 return parseError("Unterminated string");
347 if (LLVM_UNLIKELY((C & 0x1f) == C))
348 return parseError("Control character in string");
349 if (LLVM_LIKELY(C != '\\')) {
350 Out.push_back(C);
351 continue;
352 }
353 // Handle escape sequence.
354 switch (C = next()) {
355 case '"':
356 case '\\':
357 case '/':
358 Out.push_back(C);
359 break;
360 case 'b':
361 Out.push_back('\b');
362 break;
363 case 'f':
364 Out.push_back('\f');
365 break;
366 case 'n':
367 Out.push_back('\n');
368 break;
369 case 'r':
370 Out.push_back('\r');
371 break;
372 case 't':
373 Out.push_back('\t');
374 break;
375 case 'u':
376 if (!parseUnicode(Out))
377 return false;
378 break;
379 default:
380 return parseError("Invalid escape sequence");
381 }
382 }
383 return true;
384 }
385
386 static void encodeUtf8(uint32_t Rune, std::string &Out) {
387 if (Rune < 0x80) {
388 Out.push_back(Rune & 0x7F);
389 } else if (Rune < 0x800) {
390 uint8_t FirstByte = 0xC0 | ((Rune & 0x7C0) >> 6);
391 uint8_t SecondByte = 0x80 | (Rune & 0x3F);
392 Out.push_back(FirstByte);
393 Out.push_back(SecondByte);
394 } else if (Rune < 0x10000) {
395 uint8_t FirstByte = 0xE0 | ((Rune & 0xF000) >> 12);
396 uint8_t SecondByte = 0x80 | ((Rune & 0xFC0) >> 6);
397 uint8_t ThirdByte = 0x80 | (Rune & 0x3F);
398 Out.push_back(FirstByte);
399 Out.push_back(SecondByte);
400 Out.push_back(ThirdByte);
401 } else if (Rune < 0x110000) {
402 uint8_t FirstByte = 0xF0 | ((Rune & 0x1F0000) >> 18);
403 uint8_t SecondByte = 0x80 | ((Rune & 0x3F000) >> 12);
404 uint8_t ThirdByte = 0x80 | ((Rune & 0xFC0) >> 6);
405 uint8_t FourthByte = 0x80 | (Rune & 0x3F);
406 Out.push_back(FirstByte);
407 Out.push_back(SecondByte);
408 Out.push_back(ThirdByte);
409 Out.push_back(FourthByte);
410 } else {
411 llvm_unreachable("Invalid codepoint");
412 }
413 }
414
415 // Parse a UTF-16 \uNNNN escape sequence. "\u" has already been consumed.
416 // May parse several sequential escapes to ensure proper surrogate handling.
417 // We do not use ConvertUTF.h, it can't accept and replace unpaired surrogates.
418 // These are invalid Unicode but valid JSON (RFC 8259, section 8.2).
419 bool Parser::parseUnicode(std::string &Out) {
420 // Invalid UTF is not a JSON error (RFC 8529ยง8.2). It gets replaced by U+FFFD.
421 auto Invalid = [&] { Out.append(/* UTF-8 */ {'\xef', '\xbf', '\xbd'}); };
422 // Decodes 4 hex digits from the stream into Out, returns false on error.
423 auto Parse4Hex = [this](uint16_t &Out) -> bool {
424 Out = 0;
425 char Bytes[] = {next(), next(), next(), next()};
426 for (unsigned char C : Bytes) {
427 if (!std::isxdigit(C))
428 return parseError("Invalid \\u escape sequence");
429 Out <<= 4;
430 Out |= (C > '9') ? (C & ~0x20) - 'A' + 10 : (C - '0');
431 }
432 return true;
433 };
434 uint16_t First; // UTF-16 code unit from the first \u escape.
435 if (!Parse4Hex(First))
436 return false;
437
438 // We loop to allow proper surrogate-pair error handling.
439 while (true) {
440 // Case 1: the UTF-16 code unit is already a codepoint in the BMP.
441 if (LLVM_LIKELY(First < 0xD800 || First >= 0xE000)) {
442 encodeUtf8(First, Out);
443 return true;
444 }
445
446 // Case 2: it's an (unpaired) trailing surrogate.
447 if (LLVM_UNLIKELY(First >= 0xDC00)) {
448 Invalid();
449 return true;
450 }
451
452 // Case 3: it's a leading surrogate. We expect a trailing one next.
453 // Case 3a: there's no trailing \u escape. Don't advance in the stream.
454 if (!LLVM_LIKELY(P + 2 <= End && *P == '\\' && *(P + 1) == 'u')) {
455 Invalid(); // Leading surrogate was unpaired.
456 return true;
457 }
458 P += 2;
459 uint16_t Second;
460 if (!Parse4Hex(Second))
461 return false;
462 // Case 3b: there was another \u escape, but it wasn't a trailing surrogate.
463 if (LLVM_UNLIKELY(Second < 0xDC00 || Second >= 0xE000)) {
464 Invalid(); // Leading surrogate was unpaired.
465 First = Second; // Second escape still needs to be processed.
466 continue;
467 }
468 // Case 3c: a valid surrogate pair encoding an astral codepoint.
469 encodeUtf8(0x10000 | ((First - 0xD800) << 10) | (Second - 0xDC00), Out);
470 return true;
471 }
472 }
473
474 bool Parser::parseError(const char *Msg) {
475 int Line = 1;
476 const char *StartOfLine = Start;
477 for (const char *X = Start; X < P; ++X) {
478 if (*X == 0x0A) {
479 ++Line;
480 StartOfLine = X + 1;
481 }
482 }
483 Err.emplace(
484 llvm::make_unique(Msg, Line, P - StartOfLine, P - Start));
485 return false;
486 }
487 } // namespace
488
489 Expected parse(StringRef JSON) {
490 Parser P(JSON);
491 Value E = nullptr;
492 if (P.parseValue(E))
493 if (P.assertEnd())
494 return std::move(E);
495 return P.takeError();
496 }
497 char ParseError::ID = 0;
498
499 static std::vector sortedElements(const Object &O) {
500 std::vector Elements;
501 for (const auto &E : O)
502 Elements.push_back(&E);
503 llvm::sort(Elements.begin(), Elements.end(),
504 [](const Object::value_type *L, const Object::value_type *R) {
505 return L->first < R->first;
506 });
507 return Elements;
508 }
509
510 } // namespace json
511 } // namespace llvm
512
513 static void quote(llvm::raw_ostream &OS, llvm::StringRef S) {
514 OS << '\"';
515 for (unsigned char C : S) {
516 if (C == 0x22 || C == 0x5C)
517 OS << '\\';
518 if (C >= 0x20) {
519 OS << C;
520 continue;
521 }
522 OS << '\\';
523 switch (C) {
524 // A few characters are common enough to make short escapes worthwhile.
525 case '\t':
526 OS << 't';
527 break;
528 case '\n':
529 OS << 'n';
530 break;
531 case '\r':
532 OS << 'r';
533 break;
534 default:
535 OS << 'u';
536 llvm::write_hex(OS, C, llvm::HexPrintStyle::Lower, 4);
537 break;
538 }
539 }
540 OS << '\"';
541 }
542
543 enum IndenterAction {
544 Indent,
545 Outdent,
546 Newline,
547 Space,
548 };
549
550 // Prints JSON. The indenter can be used to control formatting.
551 template
552 void llvm::json::Value::print(raw_ostream &OS, const Indenter &I) const {
553 switch (Type) {
554 case T_Null:
555 OS << "null";
556 break;
557 case T_Boolean:
558 OS << (as() ? "true" : "false");
559 break;
560 case T_Number:
561 OS << format("%g", as());
562 break;
563 case T_StringRef:
564 quote(OS, as());
565 break;
566 case T_String:
567 quote(OS, as());
568 break;
569 case T_Object: {
570 bool Comma = false;
571 OS << '{';
572 I(Indent);
573 for (const auto *P : sortedElements(as())) {
574 if (Comma)
575 OS << ',';
576 Comma = true;
577 I(Newline);
578 quote(OS, P->first);
579 OS << ':';
580 I(Space);
581 P->second.print(OS, I);
582 }
583 I(Outdent);
584 if (Comma)
585 I(Newline);
586 OS << '}';
587 break;
588 }
589 case T_Array: {
590 bool Comma = false;
591 OS << '[';
592 I(Indent);
593 for (const auto &E : as()) {
594 if (Comma)
595 OS << ',';
596 Comma = true;
597 I(Newline);
598 E.print(OS, I);
599 }
600 I(Outdent);
601 if (Comma)
602 I(Newline);
603 OS << ']';
604 break;
605 }
606 }
607 }
608
609 void llvm::format_provider::format(
610 const llvm::json::Value &E, raw_ostream &OS, StringRef Options) {
611 if (Options.empty()) {
612 OS << E;
613 return;
614 }
615 unsigned IndentAmount = 0;
616 if (Options.getAsInteger(/*Radix=*/10, IndentAmount))
617 llvm_unreachable("json::Value format options should be an integer");
618 unsigned IndentLevel = 0;
619 E.print(OS, [&](IndenterAction A) {
620 switch (A) {
621 case Newline:
622 OS << '\n';
623 OS.indent(IndentLevel);
624 break;
625 case Space:
626 OS << ' ';
627 break;
628 case Indent:
629 IndentLevel += IndentAmount;
630 break;
631 case Outdent:
632 IndentLevel -= IndentAmount;
633 break;
634 };
635 });
636 }
637
638 llvm::raw_ostream &llvm::json::operator<<(raw_ostream &OS, const Value &E) {
639 E.print(OS, [](IndenterAction A) { /*ignore*/ });
640 return OS;
641 }
2929 FormatVariadicTest.cpp
3030 GlobPatternTest.cpp
3131 Host.cpp
32 JSONTest.cpp
3233 LEB128Test.cpp
3334 LineIteratorTest.cpp
3435 LockFileManagerTest.cpp
0 //===-- JSONTest.cpp - JSON unit tests --------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Support/JSON.h"
10
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
13
14 namespace llvm {
15 namespace json {
16
17 namespace {
18
19 std::string s(const Value &E) { return llvm::formatv("{0}", E).str(); }
20 std::string sp(const Value &E) { return llvm::formatv("{0:2}", E).str(); }
21
22 TEST(JSONTest, Types) {
23 EXPECT_EQ("true", s(true));
24 EXPECT_EQ("null", s(nullptr));
25 EXPECT_EQ("2.5", s(2.5));
26 EXPECT_EQ(R"("foo")", s("foo"));
27 EXPECT_EQ("[1,2,3]", s({1, 2, 3}));
28 EXPECT_EQ(R"({"x":10,"y":20})", s(Object{{"x", 10}, {"y", 20}}));
29 }
30
31 TEST(JSONTest, Constructors) {
32 // Lots of edge cases around empty and singleton init lists.
33 EXPECT_EQ("[[[3]]]", s({{{3}}}));
34 EXPECT_EQ("[[[]]]", s({{{}}}));
35 EXPECT_EQ("[[{}]]", s({{Object{}}}));
36 EXPECT_EQ(R"({"A":{"B":{}}})", s(Object{{"A", Object{{"B", Object{}}}}}));
37 EXPECT_EQ(R"({"A":{"B":{"X":"Y"}}})",
38 s(Object{{"A", Object{{"B", Object{{"X", "Y"}}}}}}));
39 }
40
41 TEST(JSONTest, StringOwnership) {
42 char X[] = "Hello";
43 Value Alias = static_cast(X);
44 X[1] = 'a';
45 EXPECT_EQ(R"("Hallo")", s(Alias));
46
47 std::string Y = "Hello";
48 Value Copy = Y;
49 Y[1] = 'a';
50 EXPECT_EQ(R"("Hello")", s(Copy));
51 }
52
53 TEST(JSONTest, CanonicalOutput) {
54 // Objects are sorted (but arrays aren't)!
55 EXPECT_EQ(R"({"a":1,"b":2,"c":3})", s(Object{{"a", 1}, {"c", 3}, {"b", 2}}));
56 EXPECT_EQ(R"(["a","c","b"])", s({"a", "c", "b"}));
57 EXPECT_EQ("3", s(3.0));
58 }
59
60 TEST(JSONTest, Escaping) {
61 std::string test = {
62 0, // Strings may contain nulls.
63 '\b', '\f', // Have mnemonics, but we escape numerically.
64 '\r', '\n', '\t', // Escaped with mnemonics.
65 'S', '\"', '\\', // Printable ASCII characters.
66 '\x7f', // Delete is not escaped.
67 '\xce', '\x94', // Non-ASCII UTF-8 is not escaped.
68 };
69
70 std::string teststring = R"("\u0000\u0008\u000c\r\n\tS\"\\)"
71 "\x7f\xCE\x94\"";
72
73 EXPECT_EQ(teststring, s(test));
74
75 EXPECT_EQ(R"({"object keys are\nescaped":true})",
76 s(Object{{"object keys are\nescaped", true}}));
77 }
78
79 TEST(JSONTest, PrettyPrinting) {
80 const char str[] = R"({
81 "empty_array": [],
82 "empty_object": {},
83 "full_array": [
84 1,
85 null
86 ],
87 "full_object": {
88 "nested_array": [
89 {
90 "property": "value"
91 }
92 ]
93 }
94 })";
95
96 EXPECT_EQ(str, sp(Object{
97 {"empty_object", Object{}},
98 {"empty_array", {}},
99 {"full_array", {1, nullptr}},
100 {"full_object",
101 Object{
102 {"nested_array",
103 {Object{
104 {"property", "value"},
105 }}},
106 }},
107 }));
108 }
109
110 TEST(JSONTest, Parse) {
111 auto Compare = [](llvm::StringRef S, Value Expected) {
112 if (auto E = parse(S)) {
113 // Compare both string forms and with operator==, in case we have bugs.
114 EXPECT_EQ(*E, Expected);
115 EXPECT_EQ(sp(*E), sp(Expected));
116 } else {
117 handleAllErrors(E.takeError(), [S](const llvm::ErrorInfoBase &E) {
118 FAIL() << "Failed to parse JSON >>> " << S << " <<<: " << E.message();
119 });
120 }
121 };
122
123 Compare(R"(true)", true);
124 Compare(R"(false)", false);
125 Compare(R"(null)", nullptr);
126
127 Compare(R"(42)", 42);
128 Compare(R"(2.5)", 2.5);
129 Compare(R"(2e50)", 2e50);
130 Compare(R"(1.2e3456789)", std::numeric_limits::infinity());
131
132 Compare(R"("foo")", "foo");
133 Compare(R"("\"\\\b\f\n\r\t")", "\"\\\b\f\n\r\t");
134 Compare(R"("\u0000")", llvm::StringRef("\0", 1));
135 Compare("\"\x7f\"", "\x7f");
136 Compare(R"("\ud801\udc37")", u8"\U00010437"); // UTF16 surrogate pair escape.
137 Compare("\"\xE2\x82\xAC\xF0\x9D\x84\x9E\"", u8"\u20ac\U0001d11e"); // UTF8
138 Compare(
139 R"("LoneLeading=\ud801, LoneTrailing=\udc01, LeadingLeadingTrailing=\ud801\ud801\udc37")",
140 u8"LoneLeading=\ufffd, LoneTrailing=\ufffd, "
141 u8"LeadingLeadingTrailing=\ufffd\U00010437"); // Invalid unicode.
142
143 Compare(R"({"":0,"":0})", Object{{"", 0}});
144 Compare(R"({"obj":{},"arr":[]})", Object{{"obj", Object{}}, {"arr", {}}});
145 Compare(R"({"\n":{"\u0000":[[[[]]]]}})",
146 Object{{"\n", Object{
147 {llvm::StringRef("\0", 1), {{{{}}}}},
148 }}});
149 Compare("\r[\n\t] ", {});
150 }
151
152 TEST(JSONTest, ParseErrors) {
153 auto ExpectErr = [](llvm::StringRef Msg, llvm::StringRef S) {
154 if (auto E = parse(S)) {
155 // Compare both string forms and with operator==, in case we have bugs.
156 FAIL() << "Parsed JSON >>> " << S << " <<< but wanted error: " << Msg;
157 } else {
158 handleAllErrors(E.takeError(), [S, Msg](const llvm::ErrorInfoBase &E) {
159 EXPECT_THAT(E.message(), testing::HasSubstr(Msg)) << S;
160 });
161 }
162 };
163 ExpectErr("Unexpected EOF", "");
164 ExpectErr("Unexpected EOF", "[");
165 ExpectErr("Text after end of document", "[][]");
166 ExpectErr("Invalid JSON value (false?)", "fuzzy");
167 ExpectErr("Expected , or ]", "[2?]");
168 ExpectErr("Expected object key", "{a:2}");
169 ExpectErr("Expected : after object key", R"({"a",2})");
170 ExpectErr("Expected , or } after object property", R"({"a":2 "b":3})");
171 ExpectErr("Invalid JSON value", R"([&%!])");
172 ExpectErr("Invalid JSON value (number?)", "1e1.0");
173 ExpectErr("Unterminated string", R"("abc\"def)");
174 ExpectErr("Control character in string", "\"abc\ndef\"");
175 ExpectErr("Invalid escape sequence", R"("\030")");
176 ExpectErr("Invalid \\u escape sequence", R"("\usuck")");
177 ExpectErr("[3:3, byte=19]", R"({
178 "valid": 1,
179 invalid: 2
180 })");
181 }
182
183 TEST(JSONTest, Inspection) {
184 llvm::Expected Doc = parse(R"(
185 {
186 "null": null,
187 "boolean": false,
188 "number": 2.78,
189 "string": "json",
190 "array": [null, true, 3.14, "hello", [1,2,3], {"time": "arrow"}],
191 "object": {"fruit": "banana"}
192 }
193 )");
194 EXPECT_TRUE(!!Doc);
195
196 Object *O = Doc->getAsObject();
197 ASSERT_TRUE(O);
198
199 EXPECT_FALSE(O->getNull("missing"));
200 EXPECT_FALSE(O->getNull("boolean"));
201 EXPECT_TRUE(O->getNull("null"));
202
203 EXPECT_EQ(O->getNumber("number"), llvm::Optional(2.78));
204 EXPECT_FALSE(O->getInteger("number"));
205 EXPECT_EQ(O->getString("string"), llvm::Optional("json"));
206 ASSERT_FALSE(O->getObject("missing"));
207 ASSERT_FALSE(O->getObject("array"));
208 ASSERT_TRUE(O->getObject("object"));
209 EXPECT_EQ(*O->getObject("object"), (Object{{"fruit", "banana"}}));
210
211 Array *A = O->getArray("array");
212 ASSERT_TRUE(A);
213 EXPECT_EQ((*A)[1].getAsBoolean(), llvm::Optional(true));
214 ASSERT_TRUE((*A)[4].getAsArray());
215 EXPECT_EQ(*(*A)[4].getAsArray(), (Array{1, 2, 3}));
216 EXPECT_EQ((*(*A)[4].getAsArray())[1].getAsInteger(),
217 llvm::Optional(2));
218 int I = 0;
219 for (Value &E : *A) {
220 if (I++ == 5) {
221 ASSERT_TRUE(E.getAsObject());
222 EXPECT_EQ(E.getAsObject()->getString("time"),
223 llvm::Optional("arrow"));
224 } else
225 EXPECT_FALSE(E.getAsObject());
226 }
227 }
228
229 // Sample struct with typical JSON-mapping rules.
230 struct CustomStruct {
231 CustomStruct() : B(false) {}
232 CustomStruct(std::string S, llvm::Optional I, bool B)
233 : S(S), I(I), B(B) {}
234 std::string S;
235 llvm::Optional I;
236 bool B;
237 };
238 inline bool operator==(const CustomStruct &L, const CustomStruct &R) {
239 return L.S == R.S && L.I == R.I && L.B == R.B;
240 }
241 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
242 const CustomStruct &S) {
243 return OS << "(" << S.S << ", " << (S.I ? std::to_string(*S.I) : "None")
244 << ", " << S.B << ")";
245 }
246 bool fromJSON(const Value &E, CustomStruct &R) {
247 ObjectMapper O(E);
248 if (!O || !O.map("str", R.S) || !O.map("int", R.I))
249 return false;
250 O.map("bool", R.B);
251 return true;
252 }
253
254 TEST(JSONTest, Deserialize) {
255 std::map> R;
256 CustomStruct ExpectedStruct = {"foo", 42, true};
257 std::map> Expected;
258 Value J = Object{
259 {"foo",
260 Array{
261 Object{
262 {"str", "foo"},
263 {"int", 42},
264 {"bool", true},
265 {"unknown", "ignored"},
266 },
267 Object{{"str", "bar"}},
268 Object{
269 {"str", "baz"}, {"bool", "string"}, // OK, deserialize ignores.
270 },
271 }}};
272 Expected["foo"] = {
273 CustomStruct("foo", 42, true),
274 CustomStruct("bar", llvm::None, false),
275 CustomStruct("baz", llvm::None, false),
276 };
277 ASSERT_TRUE(fromJSON(J, R));
278 EXPECT_EQ(R, Expected);
279
280 CustomStruct V;
281 EXPECT_FALSE(fromJSON(nullptr, V)) << "Not an object " << V;
282 EXPECT_FALSE(fromJSON(Object{}, V)) << "Missing required field " << V;
283 EXPECT_FALSE(fromJSON(Object{{"str", 1}}, V)) << "Wrong type " << V;
284 // Optional must parse as the correct type if present.
285 EXPECT_FALSE(fromJSON(Object{{"str", 1}, {"int", "string"}}, V))
286 << "Wrong type for Optional " << V;
287 }
288
289 } // namespace
290 } // namespace json
291 } // namespace llvm