1 //===--- JSON.h - JSON values, 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 /// \file 11 /// This file supports working with JSON data. 12 /// 13 /// It comprises: 14 /// 15 /// - classes which hold dynamically-typed parsed JSON structures 16 /// These are value types that can be composed, inspected, and modified. 17 /// See json::Value, and the related types json::Object and json::Array. 18 /// 19 /// - functions to parse JSON text into Values, and to serialize Values to text. 20 /// See parse(), operator<<, and format_provider. 21 /// 22 /// - a convention and helpers for mapping between json::Value and user-defined 23 /// types. See fromJSON(), ObjectMapper, and the class comment on Value. 24 /// 25 /// Typically, JSON data would be read from an external source, parsed into 26 /// a Value, and then converted into some native data structure before doing 27 /// real work on it. (And vice versa when writing). 28 /// 29 /// Other serialization mechanisms you may consider: 30 /// 31 /// - YAML is also text-based, and more human-readable than JSON. It's a more 32 /// complex format and data model, and YAML parsers aren't ubiquitous. 33 /// YAMLParser.h is a streaming parser suitable for parsing large documents 34 /// (including JSON, as YAML is a superset). It can be awkward to use 35 /// directly. YAML I/O (YAMLTraits.h) provides data mapping that is more 36 /// declarative than the toJSON/fromJSON conventions here. 37 /// 38 /// - LLVM bitstream is a space- and CPU- efficient binary format. Typically it 39 /// encodes LLVM IR ("bitcode"), but it can be a container for other data. 40 /// Low-level reader/writer libraries are in Bitcode/Bitstream*.h 41 /// 42 //===---------------------------------------------------------------------===// 43 44 #ifndef LLVM_SUPPORT_JSON_H 45 #define LLVM_SUPPORT_JSON_H 46 47 #include "llvm/ADT/DenseMap.h" 48 #include "llvm/ADT/SmallVector.h" 49 #include "llvm/ADT/StringRef.h" 50 #include "llvm/Support/Error.h" 51 #include "llvm/Support/FormatVariadic.h" 52 #include "llvm/Support/raw_ostream.h" 53 #include <map> 54 55 namespace llvm { 56 namespace json { 57 58 // === String encodings === 59 // 60 // JSON strings are character sequences (not byte sequences like std::string). 61 // We need to know the encoding, and for simplicity only support UTF-8. 62 // 63 // - When parsing, invalid UTF-8 is a syntax error like any other 64 // 65 // - When creating Values from strings, callers must ensure they are UTF-8. 66 // with asserts on, invalid UTF-8 will crash the program 67 // with asserts off, we'll substitute the replacement character (U+FFFD) 68 // Callers can use json::isUTF8() and json::fixUTF8() for validation. 69 // 70 // - When retrieving strings from Values (e.g. asString()), the result will 71 // always be valid UTF-8. 72 73 /// Returns true if \p S is valid UTF-8, which is required for use as JSON. 74 /// If it returns false, \p Offset is set to a byte offset near the first error. 75 bool isUTF8(llvm::StringRef S, size_t *ErrOffset = nullptr); 76 /// Replaces invalid UTF-8 sequences in \p S with the replacement character 77 /// (U+FFFD). The returned string is valid UTF-8. 78 /// This is much slower than isUTF8, so test that first. 79 std::string fixUTF8(llvm::StringRef S); 80 81 class Array; 82 class ObjectKey; 83 class Value; 84 template <typename T> Value toJSON(const llvm::Optional<T> &Opt); 85 86 /// An Object is a JSON object, which maps strings to heterogenous JSON values. 87 /// It simulates DenseMap<ObjectKey, Value>. ObjectKey is a maybe-owned string. 88 class Object { 89 using Storage = DenseMap<ObjectKey, Value, llvm::DenseMapInfo<StringRef>>; 90 Storage M; 91 92 public: 93 using key_type = ObjectKey; 94 using mapped_type = Value; 95 using value_type = Storage::value_type; 96 using iterator = Storage::iterator; 97 using const_iterator = Storage::const_iterator; 98 99 explicit Object() = default; 100 // KV is a trivial key-value struct for list-initialization. 101 // (using std::pair forces extra copies). 102 struct KV; 103 explicit Object(std::initializer_list<KV> Properties); 104 begin()105 iterator begin() { return M.begin(); } begin()106 const_iterator begin() const { return M.begin(); } end()107 iterator end() { return M.end(); } end()108 const_iterator end() const { return M.end(); } 109 empty()110 bool empty() const { return M.empty(); } size()111 size_t size() const { return M.size(); } 112 clear()113 void clear() { M.clear(); } 114 std::pair<iterator, bool> insert(KV E); 115 template <typename... Ts> try_emplace(const ObjectKey & K,Ts &&...Args)116 std::pair<iterator, bool> try_emplace(const ObjectKey &K, Ts &&... Args) { 117 return M.try_emplace(K, std::forward<Ts>(Args)...); 118 } 119 template <typename... Ts> try_emplace(ObjectKey && K,Ts &&...Args)120 std::pair<iterator, bool> try_emplace(ObjectKey &&K, Ts &&... Args) { 121 return M.try_emplace(std::move(K), std::forward<Ts>(Args)...); 122 } 123 find(StringRef K)124 iterator find(StringRef K) { return M.find_as(K); } find(StringRef K)125 const_iterator find(StringRef K) const { return M.find_as(K); } 126 // operator[] acts as if Value was default-constructible as null. 127 Value &operator[](const ObjectKey &K); 128 Value &operator[](ObjectKey &&K); 129 // Look up a property, returning nullptr if it doesn't exist. 130 Value *get(StringRef K); 131 const Value *get(StringRef K) const; 132 // Typed accessors return None/nullptr if 133 // - the property doesn't exist 134 // - or it has the wrong type 135 llvm::Optional<std::nullptr_t> getNull(StringRef K) const; 136 llvm::Optional<bool> getBoolean(StringRef K) const; 137 llvm::Optional<double> getNumber(StringRef K) const; 138 llvm::Optional<int64_t> getInteger(StringRef K) const; 139 llvm::Optional<llvm::StringRef> getString(StringRef K) const; 140 const json::Object *getObject(StringRef K) const; 141 json::Object *getObject(StringRef K); 142 const json::Array *getArray(StringRef K) const; 143 json::Array *getArray(StringRef K); 144 }; 145 bool operator==(const Object &LHS, const Object &RHS); 146 inline bool operator!=(const Object &LHS, const Object &RHS) { 147 return !(LHS == RHS); 148 } 149 150 /// An Array is a JSON array, which contains heterogeneous JSON values. 151 /// It simulates std::vector<Value>. 152 class Array { 153 std::vector<Value> V; 154 155 public: 156 using value_type = Value; 157 using iterator = std::vector<Value>::iterator; 158 using const_iterator = std::vector<Value>::const_iterator; 159 160 explicit Array() = default; 161 explicit Array(std::initializer_list<Value> Elements); Array(const Collection & C)162 template <typename Collection> explicit Array(const Collection &C) { 163 for (const auto &V : C) 164 emplace_back(V); 165 } 166 167 Value &operator[](size_t I) { return V[I]; } 168 const Value &operator[](size_t I) const { return V[I]; } front()169 Value &front() { return V.front(); } front()170 const Value &front() const { return V.front(); } back()171 Value &back() { return V.back(); } back()172 const Value &back() const { return V.back(); } data()173 Value *data() { return V.data(); } data()174 const Value *data() const { return V.data(); } 175 begin()176 iterator begin() { return V.begin(); } begin()177 const_iterator begin() const { return V.begin(); } end()178 iterator end() { return V.end(); } end()179 const_iterator end() const { return V.end(); } 180 empty()181 bool empty() const { return V.empty(); } size()182 size_t size() const { return V.size(); } 183 clear()184 void clear() { V.clear(); } push_back(const Value & E)185 void push_back(const Value &E) { V.push_back(E); } push_back(Value && E)186 void push_back(Value &&E) { V.push_back(std::move(E)); } emplace_back(Args &&...A)187 template <typename... Args> void emplace_back(Args &&... A) { 188 V.emplace_back(std::forward<Args>(A)...); 189 } pop_back()190 void pop_back() { V.pop_back(); } 191 // FIXME: insert() takes const_iterator since C++11, old libstdc++ disagrees. insert(iterator P,const Value & E)192 iterator insert(iterator P, const Value &E) { return V.insert(P, E); } insert(iterator P,Value && E)193 iterator insert(iterator P, Value &&E) { 194 return V.insert(P, std::move(E)); 195 } insert(iterator P,It A,It Z)196 template <typename It> iterator insert(iterator P, It A, It Z) { 197 return V.insert(P, A, Z); 198 } emplace(const_iterator P,Args &&...A)199 template <typename... Args> iterator emplace(const_iterator P, Args &&... A) { 200 return V.emplace(P, std::forward<Args>(A)...); 201 } 202 203 friend bool operator==(const Array &L, const Array &R) { return L.V == R.V; } 204 }; 205 inline bool operator!=(const Array &L, const Array &R) { return !(L == R); } 206 207 /// A Value is an JSON value of unknown type. 208 /// They can be copied, but should generally be moved. 209 /// 210 /// === Composing values === 211 /// 212 /// You can implicitly construct Values from: 213 /// - strings: std::string, SmallString, formatv, StringRef, char* 214 /// (char*, and StringRef are references, not copies!) 215 /// - numbers 216 /// - booleans 217 /// - null: nullptr 218 /// - arrays: {"foo", 42.0, false} 219 /// - serializable things: types with toJSON(const T&)->Value, found by ADL 220 /// 221 /// They can also be constructed from object/array helpers: 222 /// - json::Object is a type like map<ObjectKey, Value> 223 /// - json::Array is a type like vector<Value> 224 /// These can be list-initialized, or used to build up collections in a loop. 225 /// json::ary(Collection) converts all items in a collection to Values. 226 /// 227 /// === Inspecting values === 228 /// 229 /// Each Value is one of the JSON kinds: 230 /// null (nullptr_t) 231 /// boolean (bool) 232 /// number (double or int64) 233 /// string (StringRef) 234 /// array (json::Array) 235 /// object (json::Object) 236 /// 237 /// The kind can be queried directly, or implicitly via the typed accessors: 238 /// if (Optional<StringRef> S = E.getAsString() 239 /// assert(E.kind() == Value::String); 240 /// 241 /// Array and Object also have typed indexing accessors for easy traversal: 242 /// Expected<Value> E = parse(R"( {"options": {"font": "sans-serif"}} )"); 243 /// if (Object* O = E->getAsObject()) 244 /// if (Object* Opts = O->getObject("options")) 245 /// if (Optional<StringRef> Font = Opts->getString("font")) 246 /// assert(Opts->at("font").kind() == Value::String); 247 /// 248 /// === Converting JSON values to C++ types === 249 /// 250 /// The convention is to have a deserializer function findable via ADL: 251 /// fromJSON(const json::Value&, T&)->bool 252 /// Deserializers are provided for: 253 /// - bool 254 /// - int and int64_t 255 /// - double 256 /// - std::string 257 /// - vector<T>, where T is deserializable 258 /// - map<string, T>, where T is deserializable 259 /// - Optional<T>, where T is deserializable 260 /// ObjectMapper can help writing fromJSON() functions for object types. 261 /// 262 /// For conversion in the other direction, the serializer function is: 263 /// toJSON(const T&) -> json::Value 264 /// If this exists, then it also allows constructing Value from T, and can 265 /// be used to serialize vector<T>, map<string, T>, and Optional<T>. 266 /// 267 /// === Serialization === 268 /// 269 /// Values can be serialized to JSON: 270 /// 1) raw_ostream << Value // Basic formatting. 271 /// 2) raw_ostream << formatv("{0}", Value) // Basic formatting. 272 /// 3) raw_ostream << formatv("{0:2}", Value) // Pretty-print with indent 2. 273 /// 274 /// And parsed: 275 /// Expected<Value> E = json::parse("[1, 2, null]"); 276 /// assert(E && E->kind() == Value::Array); 277 class Value { 278 public: 279 enum Kind { 280 Null, 281 Boolean, 282 /// Number values can store both int64s and doubles at full precision, 283 /// depending on what they were constructed/parsed from. 284 Number, 285 String, 286 Array, 287 Object, 288 }; 289 290 // It would be nice to have Value() be null. But that would make {} null too. Value(const Value & M)291 Value(const Value &M) { copyFrom(M); } Value(Value && M)292 Value(Value &&M) { moveFrom(std::move(M)); } 293 Value(std::initializer_list<Value> Elements); Value(json::Array && Elements)294 Value(json::Array &&Elements) : Type(T_Array) { 295 create<json::Array>(std::move(Elements)); 296 } Value(json::Object && Properties)297 Value(json::Object &&Properties) : Type(T_Object) { 298 create<json::Object>(std::move(Properties)); 299 } 300 // Strings: types with value semantics. Must be valid UTF-8. Value(std::string V)301 Value(std::string V) : Type(T_String) { 302 if (LLVM_UNLIKELY(!isUTF8(V))) { 303 assert(false && "Invalid UTF-8 in value used as JSON"); 304 V = fixUTF8(std::move(V)); 305 } 306 create<std::string>(std::move(V)); 307 } Value(const llvm::SmallVectorImpl<char> & V)308 Value(const llvm::SmallVectorImpl<char> &V) 309 : Value(std::string(V.begin(), V.end())){}; Value(const llvm::formatv_object_base & V)310 Value(const llvm::formatv_object_base &V) : Value(V.str()){}; 311 // Strings: types with reference semantics. Must be valid UTF-8. Value(StringRef V)312 Value(StringRef V) : Type(T_StringRef) { 313 create<llvm::StringRef>(V); 314 if (LLVM_UNLIKELY(!isUTF8(V))) { 315 assert(false && "Invalid UTF-8 in value used as JSON"); 316 *this = Value(fixUTF8(V)); 317 } 318 } Value(const char * V)319 Value(const char *V) : Value(StringRef(V)) {} Value(std::nullptr_t)320 Value(std::nullptr_t) : Type(T_Null) {} 321 // Boolean (disallow implicit conversions). 322 // (The last template parameter is a dummy to keep templates distinct.) 323 template < 324 typename T, 325 typename = typename std::enable_if<std::is_same<T, bool>::value>::type, 326 bool = false> Value(T B)327 Value(T B) : Type(T_Boolean) { 328 create<bool>(B); 329 } 330 // Integers (except boolean). Must be non-narrowing convertible to int64_t. 331 template < 332 typename T, 333 typename = typename std::enable_if<std::is_integral<T>::value>::type, 334 typename = typename std::enable_if<!std::is_same<T, bool>::value>::type> Value(T I)335 Value(T I) : Type(T_Integer) { 336 create<int64_t>(int64_t{I}); 337 } 338 // Floating point. Must be non-narrowing convertible to double. 339 template <typename T, 340 typename = 341 typename std::enable_if<std::is_floating_point<T>::value>::type, 342 double * = nullptr> Value(T D)343 Value(T D) : Type(T_Double) { 344 create<double>(double{D}); 345 } 346 // Serializable types: with a toJSON(const T&)->Value function, found by ADL. 347 template <typename T, 348 typename = typename std::enable_if<std::is_same< 349 Value, decltype(toJSON(*(const T *)nullptr))>::value>, 350 Value * = nullptr> Value(const T & V)351 Value(const T &V) : Value(toJSON(V)) {} 352 353 Value &operator=(const Value &M) { 354 destroy(); 355 copyFrom(M); 356 return *this; 357 } 358 Value &operator=(Value &&M) { 359 destroy(); 360 moveFrom(std::move(M)); 361 return *this; 362 } ~Value()363 ~Value() { destroy(); } 364 kind()365 Kind kind() const { 366 switch (Type) { 367 case T_Null: 368 return Null; 369 case T_Boolean: 370 return Boolean; 371 case T_Double: 372 case T_Integer: 373 return Number; 374 case T_String: 375 case T_StringRef: 376 return String; 377 case T_Object: 378 return Object; 379 case T_Array: 380 return Array; 381 } 382 llvm_unreachable("Unknown kind"); 383 } 384 385 // Typed accessors return None/nullptr if the Value is not of this type. getAsNull()386 llvm::Optional<std::nullptr_t> getAsNull() const { 387 if (LLVM_LIKELY(Type == T_Null)) 388 return nullptr; 389 return llvm::None; 390 } getAsBoolean()391 llvm::Optional<bool> getAsBoolean() const { 392 if (LLVM_LIKELY(Type == T_Boolean)) 393 return as<bool>(); 394 return llvm::None; 395 } getAsNumber()396 llvm::Optional<double> getAsNumber() const { 397 if (LLVM_LIKELY(Type == T_Double)) 398 return as<double>(); 399 if (LLVM_LIKELY(Type == T_Integer)) 400 return as<int64_t>(); 401 return llvm::None; 402 } 403 // Succeeds if the Value is a Number, and exactly representable as int64_t. getAsInteger()404 llvm::Optional<int64_t> getAsInteger() const { 405 if (LLVM_LIKELY(Type == T_Integer)) 406 return as<int64_t>(); 407 if (LLVM_LIKELY(Type == T_Double)) { 408 double D = as<double>(); 409 if (LLVM_LIKELY(std::modf(D, &D) == 0.0 && 410 D >= double(std::numeric_limits<int64_t>::min()) && 411 D <= double(std::numeric_limits<int64_t>::max()))) 412 return D; 413 } 414 return llvm::None; 415 } getAsString()416 llvm::Optional<llvm::StringRef> getAsString() const { 417 if (Type == T_String) 418 return llvm::StringRef(as<std::string>()); 419 if (LLVM_LIKELY(Type == T_StringRef)) 420 return as<llvm::StringRef>(); 421 return llvm::None; 422 } getAsObject()423 const json::Object *getAsObject() const { 424 return LLVM_LIKELY(Type == T_Object) ? &as<json::Object>() : nullptr; 425 } getAsObject()426 json::Object *getAsObject() { 427 return LLVM_LIKELY(Type == T_Object) ? &as<json::Object>() : nullptr; 428 } getAsArray()429 const json::Array *getAsArray() const { 430 return LLVM_LIKELY(Type == T_Array) ? &as<json::Array>() : nullptr; 431 } getAsArray()432 json::Array *getAsArray() { 433 return LLVM_LIKELY(Type == T_Array) ? &as<json::Array>() : nullptr; 434 } 435 436 /// Serializes this Value to JSON, writing it to the provided stream. 437 /// The formatting is compact (no extra whitespace) and deterministic. 438 /// For pretty-printing, use the formatv() format_provider below. 439 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Value &); 440 441 private: 442 void destroy(); 443 void copyFrom(const Value &M); 444 // We allow moving from *const* Values, by marking all members as mutable! 445 // This hack is needed to support initializer-list syntax efficiently. 446 // (std::initializer_list<T> is a container of const T). 447 void moveFrom(const Value &&M); 448 friend class Array; 449 friend class Object; 450 create(U &&...V)451 template <typename T, typename... U> void create(U &&... V) { 452 new (reinterpret_cast<T *>(Union.buffer)) T(std::forward<U>(V)...); 453 } as()454 template <typename T> T &as() const { 455 return *reinterpret_cast<T *>(Union.buffer); 456 } 457 458 template <typename Indenter> 459 void print(llvm::raw_ostream &, const Indenter &) const; 460 friend struct llvm::format_provider<llvm::json::Value>; 461 462 enum ValueType : char { 463 T_Null, 464 T_Boolean, 465 T_Double, 466 T_Integer, 467 T_StringRef, 468 T_String, 469 T_Object, 470 T_Array, 471 }; 472 // All members mutable, see moveFrom(). 473 mutable ValueType Type; 474 mutable llvm::AlignedCharArrayUnion<bool, double, int64_t, llvm::StringRef, 475 std::string, json::Array, json::Object> 476 Union; 477 }; 478 479 bool operator==(const Value &, const Value &); 480 inline bool operator!=(const Value &L, const Value &R) { return !(L == R); } 481 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Value &); 482 483 /// ObjectKey is a used to capture keys in Object. Like Value but: 484 /// - only strings are allowed 485 /// - it's optimized for the string literal case (Owned == nullptr) 486 /// Like Value, strings must be UTF-8. See isUTF8 documentation for details. 487 class ObjectKey { 488 public: 489 ObjectKey(const char *S) : ObjectKey(StringRef(S)) {} 490 ObjectKey(std::string S) : Owned(new std::string(std::move(S))) { 491 if (LLVM_UNLIKELY(!isUTF8(*Owned))) { 492 assert(false && "Invalid UTF-8 in value used as JSON"); 493 *Owned = fixUTF8(std::move(*Owned)); 494 } 495 Data = *Owned; 496 } 497 ObjectKey(llvm::StringRef S) : Data(S) { 498 if (LLVM_UNLIKELY(!isUTF8(Data))) { 499 assert(false && "Invalid UTF-8 in value used as JSON"); 500 *this = ObjectKey(fixUTF8(S)); 501 } 502 } 503 ObjectKey(const llvm::SmallVectorImpl<char> &V) 504 : ObjectKey(std::string(V.begin(), V.end())) {} 505 ObjectKey(const llvm::formatv_object_base &V) : ObjectKey(V.str()) {} 506 507 ObjectKey(const ObjectKey &C) { *this = C; } 508 ObjectKey(ObjectKey &&C) : ObjectKey(static_cast<const ObjectKey &&>(C)) {} 509 ObjectKey &operator=(const ObjectKey &C) { 510 if (C.Owned) { 511 Owned.reset(new std::string(*C.Owned)); 512 Data = *Owned; 513 } else { 514 Data = C.Data; 515 } 516 return *this; 517 } 518 ObjectKey &operator=(ObjectKey &&) = default; 519 520 operator llvm::StringRef() const { return Data; } 521 std::string str() const { return Data.str(); } 522 523 private: 524 // FIXME: this is unneccesarily large (3 pointers). Pointer + length + owned 525 // could be 2 pointers at most. 526 std::unique_ptr<std::string> Owned; 527 llvm::StringRef Data; 528 }; 529 530 inline bool operator==(const ObjectKey &L, const ObjectKey &R) { 531 return llvm::StringRef(L) == llvm::StringRef(R); 532 } 533 inline bool operator!=(const ObjectKey &L, const ObjectKey &R) { 534 return !(L == R); 535 } 536 inline bool operator<(const ObjectKey &L, const ObjectKey &R) { 537 return StringRef(L) < StringRef(R); 538 } 539 540 struct Object::KV { 541 ObjectKey K; 542 Value V; 543 }; 544 545 inline Object::Object(std::initializer_list<KV> Properties) { 546 for (const auto &P : Properties) { 547 auto R = try_emplace(P.K, nullptr); 548 if (R.second) 549 R.first->getSecond().moveFrom(std::move(P.V)); 550 } 551 } 552 inline std::pair<Object::iterator, bool> Object::insert(KV E) { 553 return try_emplace(std::move(E.K), std::move(E.V)); 554 } 555 556 // Standard deserializers are provided for primitive types. 557 // See comments on Value. 558 inline bool fromJSON(const Value &E, std::string &Out) { 559 if (auto S = E.getAsString()) { 560 Out = *S; 561 return true; 562 } 563 return false; 564 } 565 inline bool fromJSON(const Value &E, int &Out) { 566 if (auto S = E.getAsInteger()) { 567 Out = *S; 568 return true; 569 } 570 return false; 571 } 572 inline bool fromJSON(const Value &E, int64_t &Out) { 573 if (auto S = E.getAsInteger()) { 574 Out = *S; 575 return true; 576 } 577 return false; 578 } 579 inline bool fromJSON(const Value &E, double &Out) { 580 if (auto S = E.getAsNumber()) { 581 Out = *S; 582 return true; 583 } 584 return false; 585 } 586 inline bool fromJSON(const Value &E, bool &Out) { 587 if (auto S = E.getAsBoolean()) { 588 Out = *S; 589 return true; 590 } 591 return false; 592 } 593 template <typename T> bool fromJSON(const Value &E, llvm::Optional<T> &Out) { 594 if (E.getAsNull()) { 595 Out = llvm::None; 596 return true; 597 } 598 T Result; 599 if (!fromJSON(E, Result)) 600 return false; 601 Out = std::move(Result); 602 return true; 603 } 604 template <typename T> bool fromJSON(const Value &E, std::vector<T> &Out) { 605 if (auto *A = E.getAsArray()) { 606 Out.clear(); 607 Out.resize(A->size()); 608 for (size_t I = 0; I < A->size(); ++I) 609 if (!fromJSON((*A)[I], Out[I])) 610 return false; 611 return true; 612 } 613 return false; 614 } 615 template <typename T> 616 bool fromJSON(const Value &E, std::map<std::string, T> &Out) { 617 if (auto *O = E.getAsObject()) { 618 Out.clear(); 619 for (const auto &KV : *O) 620 if (!fromJSON(KV.second, Out[llvm::StringRef(KV.first)])) 621 return false; 622 return true; 623 } 624 return false; 625 } 626 627 // Allow serialization of Optional<T> for supported T. 628 template <typename T> Value toJSON(const llvm::Optional<T> &Opt) { 629 return Opt ? Value(*Opt) : Value(nullptr); 630 } 631 632 /// Helper for mapping JSON objects onto protocol structs. 633 /// 634 /// Example: 635 /// \code 636 /// bool fromJSON(const Value &E, MyStruct &R) { 637 /// ObjectMapper O(E); 638 /// if (!O || !O.map("mandatory_field", R.MandatoryField)) 639 /// return false; 640 /// O.map("optional_field", R.OptionalField); 641 /// return true; 642 /// } 643 /// \endcode 644 class ObjectMapper { 645 public: 646 ObjectMapper(const Value &E) : O(E.getAsObject()) {} 647 648 /// True if the expression is an object. 649 /// Must be checked before calling map(). 650 operator bool() { return O; } 651 652 /// Maps a property to a field, if it exists. 653 template <typename T> bool map(StringRef Prop, T &Out) { 654 assert(*this && "Must check this is an object before calling map()"); 655 if (const Value *E = O->get(Prop)) 656 return fromJSON(*E, Out); 657 return false; 658 } 659 660 /// Maps a property to a field, if it exists. 661 /// (Optional requires special handling, because missing keys are OK). 662 template <typename T> bool map(StringRef Prop, llvm::Optional<T> &Out) { 663 assert(*this && "Must check this is an object before calling map()"); 664 if (const Value *E = O->get(Prop)) 665 return fromJSON(*E, Out); 666 Out = llvm::None; 667 return true; 668 } 669 670 private: 671 const Object *O; 672 }; 673 674 /// Parses the provided JSON source, or returns a ParseError. 675 /// The returned Value is self-contained and owns its strings (they do not refer 676 /// to the original source). 677 llvm::Expected<Value> parse(llvm::StringRef JSON); 678 679 class ParseError : public llvm::ErrorInfo<ParseError> { 680 const char *Msg; 681 unsigned Line, Column, Offset; 682 683 public: 684 static char ID; 685 ParseError(const char *Msg, unsigned Line, unsigned Column, unsigned Offset) 686 : Msg(Msg), Line(Line), Column(Column), Offset(Offset) {} 687 void log(llvm::raw_ostream &OS) const override { 688 OS << llvm::formatv("[{0}:{1}, byte={2}]: {3}", Line, Column, Offset, Msg); 689 } 690 std::error_code convertToErrorCode() const override { 691 return llvm::inconvertibleErrorCode(); 692 } 693 }; 694 } // namespace json 695 696 /// Allow printing json::Value with formatv(). 697 /// The default style is basic/compact formatting, like operator<<. 698 /// A format string like formatv("{0:2}", Value) pretty-prints with indent 2. 699 template <> struct format_provider<llvm::json::Value> { 700 static void format(const llvm::json::Value &, raw_ostream &, StringRef); 701 }; 702 } // namespace llvm 703 704 #endif 705