1 //===- llvm/Support/YAMLTraits.h --------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_SUPPORT_YAMLTRAITS_H 10 #define LLVM_SUPPORT_YAMLTRAITS_H 11 12 #include "llvm/ADT/ArrayRef.h" 13 #include "llvm/ADT/BitVector.h" 14 #include "llvm/ADT/SmallVector.h" 15 #include "llvm/ADT/StringExtras.h" 16 #include "llvm/ADT/StringMap.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/ADT/Twine.h" 19 #include "llvm/Support/AlignOf.h" 20 #include "llvm/Support/Allocator.h" 21 #include "llvm/Support/Endian.h" 22 #include "llvm/Support/SMLoc.h" 23 #include "llvm/Support/SourceMgr.h" 24 #include "llvm/Support/YAMLParser.h" 25 #include "llvm/Support/raw_ostream.h" 26 #include <cassert> 27 #include <map> 28 #include <memory> 29 #include <new> 30 #include <optional> 31 #include <string> 32 #include <system_error> 33 #include <type_traits> 34 #include <vector> 35 36 namespace llvm { 37 38 class VersionTuple; 39 40 namespace yaml { 41 42 enum class NodeKind : uint8_t { 43 Scalar, 44 Map, 45 Sequence, 46 }; 47 48 struct EmptyContext {}; 49 50 /// This class should be specialized by any type that needs to be converted 51 /// to/from a YAML mapping. For example: 52 /// 53 /// struct MappingTraits<MyStruct> { 54 /// static void mapping(IO &io, MyStruct &s) { 55 /// io.mapRequired("name", s.name); 56 /// io.mapRequired("size", s.size); 57 /// io.mapOptional("age", s.age); 58 /// } 59 /// }; 60 template<class T> 61 struct MappingTraits { 62 // Must provide: 63 // static void mapping(IO &io, T &fields); 64 // Optionally may provide: 65 // static std::string validate(IO &io, T &fields); 66 // static void enumInput(IO &io, T &value); 67 // 68 // The optional flow flag will cause generated YAML to use a flow mapping 69 // (e.g. { a: 0, b: 1 }): 70 // static const bool flow = true; 71 }; 72 73 /// This class is similar to MappingTraits<T> but allows you to pass in 74 /// additional context for each map operation. For example: 75 /// 76 /// struct MappingContextTraits<MyStruct, MyContext> { 77 /// static void mapping(IO &io, MyStruct &s, MyContext &c) { 78 /// io.mapRequired("name", s.name); 79 /// io.mapRequired("size", s.size); 80 /// io.mapOptional("age", s.age); 81 /// ++c.TimesMapped; 82 /// } 83 /// }; 84 template <class T, class Context> struct MappingContextTraits { 85 // Must provide: 86 // static void mapping(IO &io, T &fields, Context &Ctx); 87 // Optionally may provide: 88 // static std::string validate(IO &io, T &fields, Context &Ctx); 89 // 90 // The optional flow flag will cause generated YAML to use a flow mapping 91 // (e.g. { a: 0, b: 1 }): 92 // static const bool flow = true; 93 }; 94 95 /// This class should be specialized by any integral type that converts 96 /// to/from a YAML scalar where there is a one-to-one mapping between 97 /// in-memory values and a string in YAML. For example: 98 /// 99 /// struct ScalarEnumerationTraits<Colors> { 100 /// static void enumeration(IO &io, Colors &value) { 101 /// io.enumCase(value, "red", cRed); 102 /// io.enumCase(value, "blue", cBlue); 103 /// io.enumCase(value, "green", cGreen); 104 /// } 105 /// }; 106 template <typename T, typename Enable = void> struct ScalarEnumerationTraits { 107 // Must provide: 108 // static void enumeration(IO &io, T &value); 109 }; 110 111 /// This class should be specialized by any integer type that is a union 112 /// of bit values and the YAML representation is a flow sequence of 113 /// strings. For example: 114 /// 115 /// struct ScalarBitSetTraits<MyFlags> { 116 /// static void bitset(IO &io, MyFlags &value) { 117 /// io.bitSetCase(value, "big", flagBig); 118 /// io.bitSetCase(value, "flat", flagFlat); 119 /// io.bitSetCase(value, "round", flagRound); 120 /// } 121 /// }; 122 template <typename T, typename Enable = void> struct ScalarBitSetTraits { 123 // Must provide: 124 // static void bitset(IO &io, T &value); 125 }; 126 127 /// Describe which type of quotes should be used when quoting is necessary. 128 /// Some non-printable characters need to be double-quoted, while some others 129 /// are fine with simple-quoting, and some don't need any quoting. 130 enum class QuotingType { None, Single, Double }; 131 132 /// This class should be specialized by type that requires custom conversion 133 /// to/from a yaml scalar. For example: 134 /// 135 /// template<> 136 /// struct ScalarTraits<MyType> { 137 /// static void output(const MyType &val, void*, llvm::raw_ostream &out) { 138 /// // stream out custom formatting 139 /// out << llvm::format("%x", val); 140 /// } 141 /// static StringRef input(StringRef scalar, void*, MyType &value) { 142 /// // parse scalar and set `value` 143 /// // return empty string on success, or error string 144 /// return StringRef(); 145 /// } 146 /// static QuotingType mustQuote(StringRef) { return QuotingType::Single; } 147 /// }; 148 template <typename T, typename Enable = void> struct ScalarTraits { 149 // Must provide: 150 // 151 // Function to write the value as a string: 152 // static void output(const T &value, void *ctxt, llvm::raw_ostream &out); 153 // 154 // Function to convert a string to a value. Returns the empty 155 // StringRef on success or an error string if string is malformed: 156 // static StringRef input(StringRef scalar, void *ctxt, T &value); 157 // 158 // Function to determine if the value should be quoted. 159 // static QuotingType mustQuote(StringRef); 160 }; 161 162 /// This class should be specialized by type that requires custom conversion 163 /// to/from a YAML literal block scalar. For example: 164 /// 165 /// template <> 166 /// struct BlockScalarTraits<MyType> { 167 /// static void output(const MyType &Value, void*, llvm::raw_ostream &Out) 168 /// { 169 /// // stream out custom formatting 170 /// Out << Value; 171 /// } 172 /// static StringRef input(StringRef Scalar, void*, MyType &Value) { 173 /// // parse scalar and set `value` 174 /// // return empty string on success, or error string 175 /// return StringRef(); 176 /// } 177 /// }; 178 template <typename T> 179 struct BlockScalarTraits { 180 // Must provide: 181 // 182 // Function to write the value as a string: 183 // static void output(const T &Value, void *ctx, llvm::raw_ostream &Out); 184 // 185 // Function to convert a string to a value. Returns the empty 186 // StringRef on success or an error string if string is malformed: 187 // static StringRef input(StringRef Scalar, void *ctxt, T &Value); 188 // 189 // Optional: 190 // static StringRef inputTag(T &Val, std::string Tag) 191 // static void outputTag(const T &Val, raw_ostream &Out) 192 }; 193 194 /// This class should be specialized by type that requires custom conversion 195 /// to/from a YAML scalar with optional tags. For example: 196 /// 197 /// template <> 198 /// struct TaggedScalarTraits<MyType> { 199 /// static void output(const MyType &Value, void*, llvm::raw_ostream 200 /// &ScalarOut, llvm::raw_ostream &TagOut) 201 /// { 202 /// // stream out custom formatting including optional Tag 203 /// Out << Value; 204 /// } 205 /// static StringRef input(StringRef Scalar, StringRef Tag, void*, MyType 206 /// &Value) { 207 /// // parse scalar and set `value` 208 /// // return empty string on success, or error string 209 /// return StringRef(); 210 /// } 211 /// static QuotingType mustQuote(const MyType &Value, StringRef) { 212 /// return QuotingType::Single; 213 /// } 214 /// }; 215 template <typename T> struct TaggedScalarTraits { 216 // Must provide: 217 // 218 // Function to write the value and tag as strings: 219 // static void output(const T &Value, void *ctx, llvm::raw_ostream &ScalarOut, 220 // llvm::raw_ostream &TagOut); 221 // 222 // Function to convert a string to a value. Returns the empty 223 // StringRef on success or an error string if string is malformed: 224 // static StringRef input(StringRef Scalar, StringRef Tag, void *ctxt, T 225 // &Value); 226 // 227 // Function to determine if the value should be quoted. 228 // static QuotingType mustQuote(const T &Value, StringRef Scalar); 229 }; 230 231 /// This class should be specialized by any type that needs to be converted 232 /// to/from a YAML sequence. For example: 233 /// 234 /// template<> 235 /// struct SequenceTraits<MyContainer> { 236 /// static size_t size(IO &io, MyContainer &seq) { 237 /// return seq.size(); 238 /// } 239 /// static MyType& element(IO &, MyContainer &seq, size_t index) { 240 /// if ( index >= seq.size() ) 241 /// seq.resize(index+1); 242 /// return seq[index]; 243 /// } 244 /// }; 245 template<typename T, typename EnableIf = void> 246 struct SequenceTraits { 247 // Must provide: 248 // static size_t size(IO &io, T &seq); 249 // static T::value_type& element(IO &io, T &seq, size_t index); 250 // 251 // The following is option and will cause generated YAML to use 252 // a flow sequence (e.g. [a,b,c]). 253 // static const bool flow = true; 254 }; 255 256 /// This class should be specialized by any type for which vectors of that 257 /// type need to be converted to/from a YAML sequence. 258 template<typename T, typename EnableIf = void> 259 struct SequenceElementTraits { 260 // Must provide: 261 // static const bool flow; 262 }; 263 264 /// This class should be specialized by any type that needs to be converted 265 /// to/from a list of YAML documents. 266 template<typename T> 267 struct DocumentListTraits { 268 // Must provide: 269 // static size_t size(IO &io, T &seq); 270 // static T::value_type& element(IO &io, T &seq, size_t index); 271 }; 272 273 /// This class should be specialized by any type that needs to be converted 274 /// to/from a YAML mapping in the case where the names of the keys are not known 275 /// in advance, e.g. a string map. 276 template <typename T> 277 struct CustomMappingTraits { 278 // static void inputOne(IO &io, StringRef key, T &elem); 279 // static void output(IO &io, T &elem); 280 }; 281 282 /// This class should be specialized by any type that can be represented as 283 /// a scalar, map, or sequence, decided dynamically. For example: 284 /// 285 /// typedef std::unique_ptr<MyBase> MyPoly; 286 /// 287 /// template<> 288 /// struct PolymorphicTraits<MyPoly> { 289 /// static NodeKind getKind(const MyPoly &poly) { 290 /// return poly->getKind(); 291 /// } 292 /// static MyScalar& getAsScalar(MyPoly &poly) { 293 /// if (!poly || !isa<MyScalar>(poly)) 294 /// poly.reset(new MyScalar()); 295 /// return *cast<MyScalar>(poly.get()); 296 /// } 297 /// // ... 298 /// }; 299 template <typename T> struct PolymorphicTraits { 300 // Must provide: 301 // static NodeKind getKind(const T &poly); 302 // static scalar_type &getAsScalar(T &poly); 303 // static map_type &getAsMap(T &poly); 304 // static sequence_type &getAsSequence(T &poly); 305 }; 306 307 // Only used for better diagnostics of missing traits 308 template <typename T> 309 struct MissingTrait; 310 311 // Test if ScalarEnumerationTraits<T> is defined on type T. 312 template <class T> 313 struct has_ScalarEnumerationTraits 314 { 315 using Signature_enumeration = void (*)(class IO&, T&); 316 317 template <typename U> 318 static char test(SameType<Signature_enumeration, &U::enumeration>*); 319 320 template <typename U> 321 static double test(...); 322 323 static bool const value = 324 (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1); 325 }; 326 327 // Test if ScalarBitSetTraits<T> is defined on type T. 328 template <class T> 329 struct has_ScalarBitSetTraits 330 { 331 using Signature_bitset = void (*)(class IO&, T&); 332 333 template <typename U> 334 static char test(SameType<Signature_bitset, &U::bitset>*); 335 336 template <typename U> 337 static double test(...); 338 339 static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1); 340 }; 341 342 // Test if ScalarTraits<T> is defined on type T. 343 template <class T> 344 struct has_ScalarTraits 345 { 346 using Signature_input = StringRef (*)(StringRef, void*, T&); 347 using Signature_output = void (*)(const T&, void*, raw_ostream&); 348 using Signature_mustQuote = QuotingType (*)(StringRef); 349 350 template <typename U> 351 static char test(SameType<Signature_input, &U::input> *, 352 SameType<Signature_output, &U::output> *, 353 SameType<Signature_mustQuote, &U::mustQuote> *); 354 355 template <typename U> 356 static double test(...); 357 358 static bool const value = 359 (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); 360 }; 361 362 // Test if BlockScalarTraits<T> is defined on type T. 363 template <class T> 364 struct has_BlockScalarTraits 365 { 366 using Signature_input = StringRef (*)(StringRef, void *, T &); 367 using Signature_output = void (*)(const T &, void *, raw_ostream &); 368 369 template <typename U> 370 static char test(SameType<Signature_input, &U::input> *, 371 SameType<Signature_output, &U::output> *); 372 373 template <typename U> 374 static double test(...); 375 376 static bool const value = 377 (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1); 378 }; 379 380 // Test if TaggedScalarTraits<T> is defined on type T. 381 template <class T> struct has_TaggedScalarTraits { 382 using Signature_input = StringRef (*)(StringRef, StringRef, void *, T &); 383 using Signature_output = void (*)(const T &, void *, raw_ostream &, 384 raw_ostream &); 385 using Signature_mustQuote = QuotingType (*)(const T &, StringRef); 386 387 template <typename U> 388 static char test(SameType<Signature_input, &U::input> *, 389 SameType<Signature_output, &U::output> *, 390 SameType<Signature_mustQuote, &U::mustQuote> *); 391 392 template <typename U> static double test(...); 393 394 static bool const value = 395 (sizeof(test<TaggedScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); 396 }; 397 398 // Test if MappingContextTraits<T> is defined on type T. 399 template <class T, class Context> struct has_MappingTraits { 400 using Signature_mapping = void (*)(class IO &, T &, Context &); 401 402 template <typename U> 403 static char test(SameType<Signature_mapping, &U::mapping>*); 404 405 template <typename U> 406 static double test(...); 407 408 static bool const value = 409 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); 410 }; 411 412 // Test if MappingTraits<T> is defined on type T. 413 template <class T> struct has_MappingTraits<T, EmptyContext> { 414 using Signature_mapping = void (*)(class IO &, T &); 415 416 template <typename U> 417 static char test(SameType<Signature_mapping, &U::mapping> *); 418 419 template <typename U> static double test(...); 420 421 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); 422 }; 423 424 // Test if MappingContextTraits<T>::validate() is defined on type T. 425 template <class T, class Context> struct has_MappingValidateTraits { 426 using Signature_validate = std::string (*)(class IO &, T &, Context &); 427 428 template <typename U> 429 static char test(SameType<Signature_validate, &U::validate>*); 430 431 template <typename U> 432 static double test(...); 433 434 static bool const value = 435 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); 436 }; 437 438 // Test if MappingTraits<T>::validate() is defined on type T. 439 template <class T> struct has_MappingValidateTraits<T, EmptyContext> { 440 using Signature_validate = std::string (*)(class IO &, T &); 441 442 template <typename U> 443 static char test(SameType<Signature_validate, &U::validate> *); 444 445 template <typename U> static double test(...); 446 447 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); 448 }; 449 450 // Test if MappingContextTraits<T>::enumInput() is defined on type T. 451 template <class T, class Context> struct has_MappingEnumInputTraits { 452 using Signature_validate = void (*)(class IO &, T &); 453 454 template <typename U> 455 static char test(SameType<Signature_validate, &U::enumInput> *); 456 457 template <typename U> static double test(...); 458 459 static bool const value = 460 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1); 461 }; 462 463 // Test if MappingTraits<T>::enumInput() is defined on type T. 464 template <class T> struct has_MappingEnumInputTraits<T, EmptyContext> { 465 using Signature_validate = void (*)(class IO &, T &); 466 467 template <typename U> 468 static char test(SameType<Signature_validate, &U::enumInput> *); 469 470 template <typename U> static double test(...); 471 472 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1); 473 }; 474 475 // Test if SequenceTraits<T> is defined on type T. 476 template <class T> 477 struct has_SequenceMethodTraits 478 { 479 using Signature_size = size_t (*)(class IO&, T&); 480 481 template <typename U> 482 static char test(SameType<Signature_size, &U::size>*); 483 484 template <typename U> 485 static double test(...); 486 487 static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1); 488 }; 489 490 // Test if CustomMappingTraits<T> is defined on type T. 491 template <class T> 492 struct has_CustomMappingTraits 493 { 494 using Signature_input = void (*)(IO &io, StringRef key, T &v); 495 496 template <typename U> 497 static char test(SameType<Signature_input, &U::inputOne>*); 498 499 template <typename U> 500 static double test(...); 501 502 static bool const value = 503 (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1); 504 }; 505 506 // has_FlowTraits<int> will cause an error with some compilers because 507 // it subclasses int. Using this wrapper only instantiates the 508 // real has_FlowTraits only if the template type is a class. 509 template <typename T, bool Enabled = std::is_class_v<T>> class has_FlowTraits { 510 public: 511 static const bool value = false; 512 }; 513 514 // Some older gcc compilers don't support straight forward tests 515 // for members, so test for ambiguity cause by the base and derived 516 // classes both defining the member. 517 template <class T> 518 struct has_FlowTraits<T, true> 519 { 520 struct Fallback { bool flow; }; 521 struct Derived : T, Fallback { }; 522 523 template<typename C> 524 static char (&f(SameType<bool Fallback::*, &C::flow>*))[1]; 525 526 template<typename C> 527 static char (&f(...))[2]; 528 529 static bool const value = sizeof(f<Derived>(nullptr)) == 2; 530 }; 531 532 // Test if SequenceTraits<T> is defined on type T 533 template<typename T> 534 struct has_SequenceTraits : public std::integral_constant<bool, 535 has_SequenceMethodTraits<T>::value > { }; 536 537 // Test if DocumentListTraits<T> is defined on type T 538 template <class T> 539 struct has_DocumentListTraits 540 { 541 using Signature_size = size_t (*)(class IO &, T &); 542 543 template <typename U> 544 static char test(SameType<Signature_size, &U::size>*); 545 546 template <typename U> 547 static double test(...); 548 549 static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1); 550 }; 551 552 template <class T> struct has_PolymorphicTraits { 553 using Signature_getKind = NodeKind (*)(const T &); 554 555 template <typename U> 556 static char test(SameType<Signature_getKind, &U::getKind> *); 557 558 template <typename U> static double test(...); 559 560 static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1); 561 }; 562 563 inline bool isNumeric(StringRef S) { 564 const auto skipDigits = [](StringRef Input) { 565 return Input.ltrim("0123456789"); 566 }; 567 568 // Make S.front() and S.drop_front().front() (if S.front() is [+-]) calls 569 // safe. 570 if (S.empty() || S == "+" || S == "-") 571 return false; 572 573 if (S == ".nan" || S == ".NaN" || S == ".NAN") 574 return true; 575 576 // Infinity and decimal numbers can be prefixed with sign. 577 StringRef Tail = (S.front() == '-' || S.front() == '+') ? S.drop_front() : S; 578 579 // Check for infinity first, because checking for hex and oct numbers is more 580 // expensive. 581 if (Tail == ".inf" || Tail == ".Inf" || Tail == ".INF") 582 return true; 583 584 // Section 10.3.2 Tag Resolution 585 // YAML 1.2 Specification prohibits Base 8 and Base 16 numbers prefixed with 586 // [-+], so S should be used instead of Tail. 587 if (S.starts_with("0o")) 588 return S.size() > 2 && 589 S.drop_front(2).find_first_not_of("01234567") == StringRef::npos; 590 591 if (S.starts_with("0x")) 592 return S.size() > 2 && S.drop_front(2).find_first_not_of( 593 "0123456789abcdefABCDEF") == StringRef::npos; 594 595 // Parse float: [-+]? (\. [0-9]+ | [0-9]+ (\. [0-9]* )?) ([eE] [-+]? [0-9]+)? 596 S = Tail; 597 598 // Handle cases when the number starts with '.' and hence needs at least one 599 // digit after dot (as opposed by number which has digits before the dot), but 600 // doesn't have one. 601 if (S.starts_with(".") && 602 (S == "." || 603 (S.size() > 1 && std::strchr("0123456789", S[1]) == nullptr))) 604 return false; 605 606 if (S.starts_with("E") || S.starts_with("e")) 607 return false; 608 609 enum ParseState { 610 Default, 611 FoundDot, 612 FoundExponent, 613 }; 614 ParseState State = Default; 615 616 S = skipDigits(S); 617 618 // Accept decimal integer. 619 if (S.empty()) 620 return true; 621 622 if (S.front() == '.') { 623 State = FoundDot; 624 S = S.drop_front(); 625 } else if (S.front() == 'e' || S.front() == 'E') { 626 State = FoundExponent; 627 S = S.drop_front(); 628 } else { 629 return false; 630 } 631 632 if (State == FoundDot) { 633 S = skipDigits(S); 634 if (S.empty()) 635 return true; 636 637 if (S.front() == 'e' || S.front() == 'E') { 638 State = FoundExponent; 639 S = S.drop_front(); 640 } else { 641 return false; 642 } 643 } 644 645 assert(State == FoundExponent && "Should have found exponent at this point."); 646 if (S.empty()) 647 return false; 648 649 if (S.front() == '+' || S.front() == '-') { 650 S = S.drop_front(); 651 if (S.empty()) 652 return false; 653 } 654 655 return skipDigits(S).empty(); 656 } 657 658 inline bool isNull(StringRef S) { 659 return S == "null" || S == "Null" || S == "NULL" || S == "~"; 660 } 661 662 inline bool isBool(StringRef S) { 663 // FIXME: using parseBool is causing multiple tests to fail. 664 return S == "true" || S == "True" || S == "TRUE" || S == "false" || 665 S == "False" || S == "FALSE"; 666 } 667 668 // 5.1. Character Set 669 // The allowed character range explicitly excludes the C0 control block #x0-#x1F 670 // (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1 671 // control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate 672 // block #xD800-#xDFFF, #xFFFE, and #xFFFF. 673 // 674 // Some strings are valid YAML values even unquoted, but without quotes are 675 // interpreted as non-string type, for instance null, boolean or numeric values. 676 // If ForcePreserveAsString is set, such strings are quoted. 677 inline QuotingType needsQuotes(StringRef S, bool ForcePreserveAsString = true) { 678 if (S.empty()) 679 return QuotingType::Single; 680 681 QuotingType MaxQuotingNeeded = QuotingType::None; 682 if (isSpace(static_cast<unsigned char>(S.front())) || 683 isSpace(static_cast<unsigned char>(S.back()))) 684 MaxQuotingNeeded = QuotingType::Single; 685 if (ForcePreserveAsString) { 686 if (isNull(S)) 687 MaxQuotingNeeded = QuotingType::Single; 688 if (isBool(S)) 689 MaxQuotingNeeded = QuotingType::Single; 690 if (isNumeric(S)) 691 MaxQuotingNeeded = QuotingType::Single; 692 } 693 694 // 7.3.3 Plain Style 695 // Plain scalars must not begin with most indicators, as this would cause 696 // ambiguity with other YAML constructs. 697 if (std::strchr(R"(-?:\,[]{}#&*!|>'"%@`)", S[0]) != nullptr) 698 MaxQuotingNeeded = QuotingType::Single; 699 700 for (unsigned char C : S) { 701 // Alphanum is safe. 702 if (isAlnum(C)) 703 continue; 704 705 switch (C) { 706 // Safe scalar characters. 707 case '_': 708 case '-': 709 case '^': 710 case '.': 711 case ',': 712 case ' ': 713 // TAB (0x9) is allowed in unquoted strings. 714 case 0x9: 715 continue; 716 // LF(0xA) and CR(0xD) may delimit values and so require at least single 717 // quotes. LLVM YAML parser cannot handle single quoted multiline so use 718 // double quoting to produce valid YAML. 719 case 0xA: 720 case 0xD: 721 return QuotingType::Double; 722 // DEL (0x7F) are excluded from the allowed character range. 723 case 0x7F: 724 return QuotingType::Double; 725 // Forward slash is allowed to be unquoted, but we quote it anyway. We have 726 // many tests that use FileCheck against YAML output, and this output often 727 // contains paths. If we quote backslashes but not forward slashes then 728 // paths will come out either quoted or unquoted depending on which platform 729 // the test is run on, making FileCheck comparisons difficult. 730 case '/': 731 default: { 732 // C0 control block (0x0 - 0x1F) is excluded from the allowed character 733 // range. 734 if (C <= 0x1F) 735 return QuotingType::Double; 736 737 // Always double quote UTF-8. 738 if ((C & 0x80) != 0) 739 return QuotingType::Double; 740 741 // The character is not safe, at least simple quoting needed. 742 MaxQuotingNeeded = QuotingType::Single; 743 } 744 } 745 } 746 747 return MaxQuotingNeeded; 748 } 749 750 template <typename T, typename Context> 751 struct missingTraits 752 : public std::integral_constant<bool, 753 !has_ScalarEnumerationTraits<T>::value && 754 !has_ScalarBitSetTraits<T>::value && 755 !has_ScalarTraits<T>::value && 756 !has_BlockScalarTraits<T>::value && 757 !has_TaggedScalarTraits<T>::value && 758 !has_MappingTraits<T, Context>::value && 759 !has_SequenceTraits<T>::value && 760 !has_CustomMappingTraits<T>::value && 761 !has_DocumentListTraits<T>::value && 762 !has_PolymorphicTraits<T>::value> {}; 763 764 template <typename T, typename Context> 765 struct validatedMappingTraits 766 : public std::integral_constant< 767 bool, has_MappingTraits<T, Context>::value && 768 has_MappingValidateTraits<T, Context>::value> {}; 769 770 template <typename T, typename Context> 771 struct unvalidatedMappingTraits 772 : public std::integral_constant< 773 bool, has_MappingTraits<T, Context>::value && 774 !has_MappingValidateTraits<T, Context>::value> {}; 775 776 // Base class for Input and Output. 777 class IO { 778 public: 779 IO(void *Ctxt = nullptr); 780 virtual ~IO(); 781 782 virtual bool outputting() const = 0; 783 784 virtual unsigned beginSequence() = 0; 785 virtual bool preflightElement(unsigned, void *&) = 0; 786 virtual void postflightElement(void*) = 0; 787 virtual void endSequence() = 0; 788 virtual bool canElideEmptySequence() = 0; 789 790 virtual unsigned beginFlowSequence() = 0; 791 virtual bool preflightFlowElement(unsigned, void *&) = 0; 792 virtual void postflightFlowElement(void*) = 0; 793 virtual void endFlowSequence() = 0; 794 795 virtual bool mapTag(StringRef Tag, bool Default=false) = 0; 796 virtual void beginMapping() = 0; 797 virtual void endMapping() = 0; 798 virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0; 799 virtual void postflightKey(void*) = 0; 800 virtual std::vector<StringRef> keys() = 0; 801 802 virtual void beginFlowMapping() = 0; 803 virtual void endFlowMapping() = 0; 804 805 virtual void beginEnumScalar() = 0; 806 virtual bool matchEnumScalar(const char*, bool) = 0; 807 virtual bool matchEnumFallback() = 0; 808 virtual void endEnumScalar() = 0; 809 810 virtual bool beginBitSetScalar(bool &) = 0; 811 virtual bool bitSetMatch(const char*, bool) = 0; 812 virtual void endBitSetScalar() = 0; 813 814 virtual void scalarString(StringRef &, QuotingType) = 0; 815 virtual void blockScalarString(StringRef &) = 0; 816 virtual void scalarTag(std::string &) = 0; 817 818 virtual NodeKind getNodeKind() = 0; 819 820 virtual void setError(const Twine &) = 0; 821 virtual void setAllowUnknownKeys(bool Allow); 822 823 template <typename T> 824 void enumCase(T &Val, const char* Str, const T ConstVal) { 825 if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) { 826 Val = ConstVal; 827 } 828 } 829 830 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 831 template <typename T> 832 void enumCase(T &Val, const char* Str, const uint32_t ConstVal) { 833 if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) { 834 Val = ConstVal; 835 } 836 } 837 838 template <typename FBT, typename T> 839 void enumFallback(T &Val) { 840 if (matchEnumFallback()) { 841 EmptyContext Context; 842 // FIXME: Force integral conversion to allow strong typedefs to convert. 843 FBT Res = static_cast<typename FBT::BaseType>(Val); 844 yamlize(*this, Res, true, Context); 845 Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res)); 846 } 847 } 848 849 template <typename T> 850 void bitSetCase(T &Val, const char* Str, const T ConstVal) { 851 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 852 Val = static_cast<T>(Val | ConstVal); 853 } 854 } 855 856 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 857 template <typename T> 858 void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) { 859 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 860 Val = static_cast<T>(Val | ConstVal); 861 } 862 } 863 864 template <typename T> 865 void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) { 866 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 867 Val = Val | ConstVal; 868 } 869 870 template <typename T> 871 void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal, 872 uint32_t Mask) { 873 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 874 Val = Val | ConstVal; 875 } 876 877 void *getContext() const; 878 void setContext(void *); 879 880 template <typename T> void mapRequired(const char *Key, T &Val) { 881 EmptyContext Ctx; 882 this->processKey(Key, Val, true, Ctx); 883 } 884 885 template <typename T, typename Context> 886 void mapRequired(const char *Key, T &Val, Context &Ctx) { 887 this->processKey(Key, Val, true, Ctx); 888 } 889 890 template <typename T> void mapOptional(const char *Key, T &Val) { 891 EmptyContext Ctx; 892 mapOptionalWithContext(Key, Val, Ctx); 893 } 894 895 template <typename T, typename DefaultT> 896 void mapOptional(const char *Key, T &Val, const DefaultT &Default) { 897 EmptyContext Ctx; 898 mapOptionalWithContext(Key, Val, Default, Ctx); 899 } 900 901 template <typename T, typename Context> 902 std::enable_if_t<has_SequenceTraits<T>::value, void> 903 mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { 904 // omit key/value instead of outputting empty sequence 905 if (this->canElideEmptySequence() && !(Val.begin() != Val.end())) 906 return; 907 this->processKey(Key, Val, false, Ctx); 908 } 909 910 template <typename T, typename Context> 911 void mapOptionalWithContext(const char *Key, std::optional<T> &Val, 912 Context &Ctx) { 913 this->processKeyWithDefault(Key, Val, std::optional<T>(), 914 /*Required=*/false, Ctx); 915 } 916 917 template <typename T, typename Context> 918 std::enable_if_t<!has_SequenceTraits<T>::value, void> 919 mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { 920 this->processKey(Key, Val, false, Ctx); 921 } 922 923 template <typename T, typename Context, typename DefaultT> 924 void mapOptionalWithContext(const char *Key, T &Val, const DefaultT &Default, 925 Context &Ctx) { 926 static_assert(std::is_convertible<DefaultT, T>::value, 927 "Default type must be implicitly convertible to value type!"); 928 this->processKeyWithDefault(Key, Val, static_cast<const T &>(Default), 929 false, Ctx); 930 } 931 932 private: 933 template <typename T, typename Context> 934 void processKeyWithDefault(const char *Key, std::optional<T> &Val, 935 const std::optional<T> &DefaultValue, 936 bool Required, Context &Ctx); 937 938 template <typename T, typename Context> 939 void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue, 940 bool Required, Context &Ctx) { 941 void *SaveInfo; 942 bool UseDefault; 943 const bool sameAsDefault = outputting() && Val == DefaultValue; 944 if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault, 945 SaveInfo) ) { 946 yamlize(*this, Val, Required, Ctx); 947 this->postflightKey(SaveInfo); 948 } 949 else { 950 if ( UseDefault ) 951 Val = DefaultValue; 952 } 953 } 954 955 template <typename T, typename Context> 956 void processKey(const char *Key, T &Val, bool Required, Context &Ctx) { 957 void *SaveInfo; 958 bool UseDefault; 959 if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) { 960 yamlize(*this, Val, Required, Ctx); 961 this->postflightKey(SaveInfo); 962 } 963 } 964 965 private: 966 void *Ctxt; 967 }; 968 969 namespace detail { 970 971 template <typename T, typename Context> 972 void doMapping(IO &io, T &Val, Context &Ctx) { 973 MappingContextTraits<T, Context>::mapping(io, Val, Ctx); 974 } 975 976 template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) { 977 MappingTraits<T>::mapping(io, Val); 978 } 979 980 } // end namespace detail 981 982 template <typename T> 983 std::enable_if_t<has_ScalarEnumerationTraits<T>::value, void> 984 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 985 io.beginEnumScalar(); 986 ScalarEnumerationTraits<T>::enumeration(io, Val); 987 io.endEnumScalar(); 988 } 989 990 template <typename T> 991 std::enable_if_t<has_ScalarBitSetTraits<T>::value, void> 992 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 993 bool DoClear; 994 if ( io.beginBitSetScalar(DoClear) ) { 995 if ( DoClear ) 996 Val = T(); 997 ScalarBitSetTraits<T>::bitset(io, Val); 998 io.endBitSetScalar(); 999 } 1000 } 1001 1002 template <typename T> 1003 std::enable_if_t<has_ScalarTraits<T>::value, void> yamlize(IO &io, T &Val, bool, 1004 EmptyContext &Ctx) { 1005 if ( io.outputting() ) { 1006 SmallString<128> Storage; 1007 raw_svector_ostream Buffer(Storage); 1008 ScalarTraits<T>::output(Val, io.getContext(), Buffer); 1009 StringRef Str = Buffer.str(); 1010 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); 1011 } 1012 else { 1013 StringRef Str; 1014 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); 1015 StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val); 1016 if ( !Result.empty() ) { 1017 io.setError(Twine(Result)); 1018 } 1019 } 1020 } 1021 1022 template <typename T> 1023 std::enable_if_t<has_BlockScalarTraits<T>::value, void> 1024 yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { 1025 if (YamlIO.outputting()) { 1026 std::string Storage; 1027 raw_string_ostream Buffer(Storage); 1028 BlockScalarTraits<T>::output(Val, YamlIO.getContext(), Buffer); 1029 StringRef Str(Storage); 1030 YamlIO.blockScalarString(Str); 1031 } else { 1032 StringRef Str; 1033 YamlIO.blockScalarString(Str); 1034 StringRef Result = 1035 BlockScalarTraits<T>::input(Str, YamlIO.getContext(), Val); 1036 if (!Result.empty()) 1037 YamlIO.setError(Twine(Result)); 1038 } 1039 } 1040 1041 template <typename T> 1042 std::enable_if_t<has_TaggedScalarTraits<T>::value, void> 1043 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 1044 if (io.outputting()) { 1045 std::string ScalarStorage, TagStorage; 1046 raw_string_ostream ScalarBuffer(ScalarStorage), TagBuffer(TagStorage); 1047 TaggedScalarTraits<T>::output(Val, io.getContext(), ScalarBuffer, 1048 TagBuffer); 1049 io.scalarTag(TagStorage); 1050 StringRef ScalarStr(ScalarStorage); 1051 io.scalarString(ScalarStr, 1052 TaggedScalarTraits<T>::mustQuote(Val, ScalarStr)); 1053 } else { 1054 std::string Tag; 1055 io.scalarTag(Tag); 1056 StringRef Str; 1057 io.scalarString(Str, QuotingType::None); 1058 StringRef Result = 1059 TaggedScalarTraits<T>::input(Str, Tag, io.getContext(), Val); 1060 if (!Result.empty()) { 1061 io.setError(Twine(Result)); 1062 } 1063 } 1064 } 1065 1066 namespace detail { 1067 1068 template <typename T, typename Context> 1069 std::string doValidate(IO &io, T &Val, Context &Ctx) { 1070 return MappingContextTraits<T, Context>::validate(io, Val, Ctx); 1071 } 1072 1073 template <typename T> std::string doValidate(IO &io, T &Val, EmptyContext &) { 1074 return MappingTraits<T>::validate(io, Val); 1075 } 1076 1077 } // namespace detail 1078 1079 template <typename T, typename Context> 1080 std::enable_if_t<validatedMappingTraits<T, Context>::value, void> 1081 yamlize(IO &io, T &Val, bool, Context &Ctx) { 1082 if (has_FlowTraits<MappingTraits<T>>::value) 1083 io.beginFlowMapping(); 1084 else 1085 io.beginMapping(); 1086 if (io.outputting()) { 1087 std::string Err = detail::doValidate(io, Val, Ctx); 1088 if (!Err.empty()) { 1089 errs() << Err << "\n"; 1090 assert(Err.empty() && "invalid struct trying to be written as yaml"); 1091 } 1092 } 1093 detail::doMapping(io, Val, Ctx); 1094 if (!io.outputting()) { 1095 std::string Err = detail::doValidate(io, Val, Ctx); 1096 if (!Err.empty()) 1097 io.setError(Err); 1098 } 1099 if (has_FlowTraits<MappingTraits<T>>::value) 1100 io.endFlowMapping(); 1101 else 1102 io.endMapping(); 1103 } 1104 1105 template <typename T, typename Context> 1106 std::enable_if_t<!has_MappingEnumInputTraits<T, Context>::value, bool> 1107 yamlizeMappingEnumInput(IO &io, T &Val) { 1108 return false; 1109 } 1110 1111 template <typename T, typename Context> 1112 std::enable_if_t<has_MappingEnumInputTraits<T, Context>::value, bool> 1113 yamlizeMappingEnumInput(IO &io, T &Val) { 1114 if (io.outputting()) 1115 return false; 1116 1117 io.beginEnumScalar(); 1118 MappingTraits<T>::enumInput(io, Val); 1119 bool Matched = !io.matchEnumFallback(); 1120 io.endEnumScalar(); 1121 return Matched; 1122 } 1123 1124 template <typename T, typename Context> 1125 std::enable_if_t<unvalidatedMappingTraits<T, Context>::value, void> 1126 yamlize(IO &io, T &Val, bool, Context &Ctx) { 1127 if (yamlizeMappingEnumInput<T, Context>(io, Val)) 1128 return; 1129 if (has_FlowTraits<MappingTraits<T>>::value) { 1130 io.beginFlowMapping(); 1131 detail::doMapping(io, Val, Ctx); 1132 io.endFlowMapping(); 1133 } else { 1134 io.beginMapping(); 1135 detail::doMapping(io, Val, Ctx); 1136 io.endMapping(); 1137 } 1138 } 1139 1140 template <typename T> 1141 std::enable_if_t<has_CustomMappingTraits<T>::value, void> 1142 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 1143 if ( io.outputting() ) { 1144 io.beginMapping(); 1145 CustomMappingTraits<T>::output(io, Val); 1146 io.endMapping(); 1147 } else { 1148 io.beginMapping(); 1149 for (StringRef key : io.keys()) 1150 CustomMappingTraits<T>::inputOne(io, key, Val); 1151 io.endMapping(); 1152 } 1153 } 1154 1155 template <typename T> 1156 std::enable_if_t<has_PolymorphicTraits<T>::value, void> 1157 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 1158 switch (io.outputting() ? PolymorphicTraits<T>::getKind(Val) 1159 : io.getNodeKind()) { 1160 case NodeKind::Scalar: 1161 return yamlize(io, PolymorphicTraits<T>::getAsScalar(Val), true, Ctx); 1162 case NodeKind::Map: 1163 return yamlize(io, PolymorphicTraits<T>::getAsMap(Val), true, Ctx); 1164 case NodeKind::Sequence: 1165 return yamlize(io, PolymorphicTraits<T>::getAsSequence(Val), true, Ctx); 1166 } 1167 } 1168 1169 template <typename T> 1170 std::enable_if_t<missingTraits<T, EmptyContext>::value, void> 1171 yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { 1172 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1173 } 1174 1175 template <typename T, typename Context> 1176 std::enable_if_t<has_SequenceTraits<T>::value, void> 1177 yamlize(IO &io, T &Seq, bool, Context &Ctx) { 1178 if ( has_FlowTraits< SequenceTraits<T>>::value ) { 1179 unsigned incnt = io.beginFlowSequence(); 1180 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 1181 for(unsigned i=0; i < count; ++i) { 1182 void *SaveInfo; 1183 if ( io.preflightFlowElement(i, SaveInfo) ) { 1184 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); 1185 io.postflightFlowElement(SaveInfo); 1186 } 1187 } 1188 io.endFlowSequence(); 1189 } 1190 else { 1191 unsigned incnt = io.beginSequence(); 1192 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 1193 for(unsigned i=0; i < count; ++i) { 1194 void *SaveInfo; 1195 if ( io.preflightElement(i, SaveInfo) ) { 1196 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx); 1197 io.postflightElement(SaveInfo); 1198 } 1199 } 1200 io.endSequence(); 1201 } 1202 } 1203 1204 template<> 1205 struct ScalarTraits<bool> { 1206 static void output(const bool &, void* , raw_ostream &); 1207 static StringRef input(StringRef, void *, bool &); 1208 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1209 }; 1210 1211 template<> 1212 struct ScalarTraits<StringRef> { 1213 static void output(const StringRef &, void *, raw_ostream &); 1214 static StringRef input(StringRef, void *, StringRef &); 1215 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } 1216 }; 1217 1218 template<> 1219 struct ScalarTraits<std::string> { 1220 static void output(const std::string &, void *, raw_ostream &); 1221 static StringRef input(StringRef, void *, std::string &); 1222 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } 1223 }; 1224 1225 template<> 1226 struct ScalarTraits<uint8_t> { 1227 static void output(const uint8_t &, void *, raw_ostream &); 1228 static StringRef input(StringRef, void *, uint8_t &); 1229 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1230 }; 1231 1232 template<> 1233 struct ScalarTraits<uint16_t> { 1234 static void output(const uint16_t &, void *, raw_ostream &); 1235 static StringRef input(StringRef, void *, uint16_t &); 1236 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1237 }; 1238 1239 template<> 1240 struct ScalarTraits<uint32_t> { 1241 static void output(const uint32_t &, void *, raw_ostream &); 1242 static StringRef input(StringRef, void *, uint32_t &); 1243 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1244 }; 1245 1246 template<> 1247 struct ScalarTraits<uint64_t> { 1248 static void output(const uint64_t &, void *, raw_ostream &); 1249 static StringRef input(StringRef, void *, uint64_t &); 1250 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1251 }; 1252 1253 template<> 1254 struct ScalarTraits<int8_t> { 1255 static void output(const int8_t &, void *, raw_ostream &); 1256 static StringRef input(StringRef, void *, int8_t &); 1257 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1258 }; 1259 1260 template<> 1261 struct ScalarTraits<int16_t> { 1262 static void output(const int16_t &, void *, raw_ostream &); 1263 static StringRef input(StringRef, void *, int16_t &); 1264 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1265 }; 1266 1267 template<> 1268 struct ScalarTraits<int32_t> { 1269 static void output(const int32_t &, void *, raw_ostream &); 1270 static StringRef input(StringRef, void *, int32_t &); 1271 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1272 }; 1273 1274 template<> 1275 struct ScalarTraits<int64_t> { 1276 static void output(const int64_t &, void *, raw_ostream &); 1277 static StringRef input(StringRef, void *, int64_t &); 1278 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1279 }; 1280 1281 template<> 1282 struct ScalarTraits<float> { 1283 static void output(const float &, void *, raw_ostream &); 1284 static StringRef input(StringRef, void *, float &); 1285 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1286 }; 1287 1288 template<> 1289 struct ScalarTraits<double> { 1290 static void output(const double &, void *, raw_ostream &); 1291 static StringRef input(StringRef, void *, double &); 1292 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1293 }; 1294 1295 // For endian types, we use existing scalar Traits class for the underlying 1296 // type. This way endian aware types are supported whenever the traits are 1297 // defined for the underlying type. 1298 template <typename value_type, llvm::endianness endian, size_t alignment> 1299 struct ScalarTraits<support::detail::packed_endian_specific_integral< 1300 value_type, endian, alignment>, 1301 std::enable_if_t<has_ScalarTraits<value_type>::value>> { 1302 using endian_type = 1303 support::detail::packed_endian_specific_integral<value_type, endian, 1304 alignment>; 1305 1306 static void output(const endian_type &E, void *Ctx, raw_ostream &Stream) { 1307 ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream); 1308 } 1309 1310 static StringRef input(StringRef Str, void *Ctx, endian_type &E) { 1311 value_type V; 1312 auto R = ScalarTraits<value_type>::input(Str, Ctx, V); 1313 E = static_cast<endian_type>(V); 1314 return R; 1315 } 1316 1317 static QuotingType mustQuote(StringRef Str) { 1318 return ScalarTraits<value_type>::mustQuote(Str); 1319 } 1320 }; 1321 1322 template <typename value_type, llvm::endianness endian, size_t alignment> 1323 struct ScalarEnumerationTraits< 1324 support::detail::packed_endian_specific_integral<value_type, endian, 1325 alignment>, 1326 std::enable_if_t<has_ScalarEnumerationTraits<value_type>::value>> { 1327 using endian_type = 1328 support::detail::packed_endian_specific_integral<value_type, endian, 1329 alignment>; 1330 1331 static void enumeration(IO &io, endian_type &E) { 1332 value_type V = E; 1333 ScalarEnumerationTraits<value_type>::enumeration(io, V); 1334 E = V; 1335 } 1336 }; 1337 1338 template <typename value_type, llvm::endianness endian, size_t alignment> 1339 struct ScalarBitSetTraits< 1340 support::detail::packed_endian_specific_integral<value_type, endian, 1341 alignment>, 1342 std::enable_if_t<has_ScalarBitSetTraits<value_type>::value>> { 1343 using endian_type = 1344 support::detail::packed_endian_specific_integral<value_type, endian, 1345 alignment>; 1346 static void bitset(IO &io, endian_type &E) { 1347 value_type V = E; 1348 ScalarBitSetTraits<value_type>::bitset(io, V); 1349 E = V; 1350 } 1351 }; 1352 1353 // Utility for use within MappingTraits<>::mapping() method 1354 // to [de]normalize an object for use with YAML conversion. 1355 template <typename TNorm, typename TFinal> 1356 struct MappingNormalization { 1357 MappingNormalization(IO &i_o, TFinal &Obj) 1358 : io(i_o), BufPtr(nullptr), Result(Obj) { 1359 if ( io.outputting() ) { 1360 BufPtr = new (&Buffer) TNorm(io, Obj); 1361 } 1362 else { 1363 BufPtr = new (&Buffer) TNorm(io); 1364 } 1365 } 1366 1367 ~MappingNormalization() { 1368 if ( ! io.outputting() ) { 1369 Result = BufPtr->denormalize(io); 1370 } 1371 BufPtr->~TNorm(); 1372 } 1373 1374 TNorm* operator->() { return BufPtr; } 1375 1376 private: 1377 using Storage = AlignedCharArrayUnion<TNorm>; 1378 1379 Storage Buffer; 1380 IO &io; 1381 TNorm *BufPtr; 1382 TFinal &Result; 1383 }; 1384 1385 // Utility for use within MappingTraits<>::mapping() method 1386 // to [de]normalize an object for use with YAML conversion. 1387 template <typename TNorm, typename TFinal> 1388 struct MappingNormalizationHeap { 1389 MappingNormalizationHeap(IO &i_o, TFinal &Obj, BumpPtrAllocator *allocator) 1390 : io(i_o), Result(Obj) { 1391 if ( io.outputting() ) { 1392 BufPtr = new (&Buffer) TNorm(io, Obj); 1393 } 1394 else if (allocator) { 1395 BufPtr = allocator->Allocate<TNorm>(); 1396 new (BufPtr) TNorm(io); 1397 } else { 1398 BufPtr = new TNorm(io); 1399 } 1400 } 1401 1402 ~MappingNormalizationHeap() { 1403 if ( io.outputting() ) { 1404 BufPtr->~TNorm(); 1405 } 1406 else { 1407 Result = BufPtr->denormalize(io); 1408 } 1409 } 1410 1411 TNorm* operator->() { return BufPtr; } 1412 1413 private: 1414 using Storage = AlignedCharArrayUnion<TNorm>; 1415 1416 Storage Buffer; 1417 IO &io; 1418 TNorm *BufPtr = nullptr; 1419 TFinal &Result; 1420 }; 1421 1422 /// 1423 /// The Input class is used to parse a yaml document into in-memory structs 1424 /// and vectors. 1425 /// 1426 /// It works by using YAMLParser to do a syntax parse of the entire yaml 1427 /// document, then the Input class builds a graph of HNodes which wraps 1428 /// each yaml Node. The extra layer is buffering. The low level yaml 1429 /// parser only lets you look at each node once. The buffering layer lets 1430 /// you search and interate multiple times. This is necessary because 1431 /// the mapRequired() method calls may not be in the same order 1432 /// as the keys in the document. 1433 /// 1434 class Input : public IO { 1435 public: 1436 // Construct a yaml Input object from a StringRef and optional 1437 // user-data. The DiagHandler can be specified to provide 1438 // alternative error reporting. 1439 Input(StringRef InputContent, 1440 void *Ctxt = nullptr, 1441 SourceMgr::DiagHandlerTy DiagHandler = nullptr, 1442 void *DiagHandlerCtxt = nullptr); 1443 Input(MemoryBufferRef Input, 1444 void *Ctxt = nullptr, 1445 SourceMgr::DiagHandlerTy DiagHandler = nullptr, 1446 void *DiagHandlerCtxt = nullptr); 1447 ~Input() override; 1448 1449 // Check if there was an syntax or semantic error during parsing. 1450 std::error_code error(); 1451 1452 private: 1453 bool outputting() const override; 1454 bool mapTag(StringRef, bool) override; 1455 void beginMapping() override; 1456 void endMapping() override; 1457 bool preflightKey(const char *, bool, bool, bool &, void *&) override; 1458 void postflightKey(void *) override; 1459 std::vector<StringRef> keys() override; 1460 void beginFlowMapping() override; 1461 void endFlowMapping() override; 1462 unsigned beginSequence() override; 1463 void endSequence() override; 1464 bool preflightElement(unsigned index, void *&) override; 1465 void postflightElement(void *) override; 1466 unsigned beginFlowSequence() override; 1467 bool preflightFlowElement(unsigned , void *&) override; 1468 void postflightFlowElement(void *) override; 1469 void endFlowSequence() override; 1470 void beginEnumScalar() override; 1471 bool matchEnumScalar(const char*, bool) override; 1472 bool matchEnumFallback() override; 1473 void endEnumScalar() override; 1474 bool beginBitSetScalar(bool &) override; 1475 bool bitSetMatch(const char *, bool ) override; 1476 void endBitSetScalar() override; 1477 void scalarString(StringRef &, QuotingType) override; 1478 void blockScalarString(StringRef &) override; 1479 void scalarTag(std::string &) override; 1480 NodeKind getNodeKind() override; 1481 void setError(const Twine &message) override; 1482 bool canElideEmptySequence() override; 1483 1484 class HNode { 1485 public: 1486 HNode(Node *n) : _node(n) {} 1487 1488 static bool classof(const HNode *) { return true; } 1489 1490 Node *_node; 1491 }; 1492 1493 class EmptyHNode : public HNode { 1494 public: 1495 EmptyHNode(Node *n) : HNode(n) { } 1496 1497 static bool classof(const HNode *n) { return NullNode::classof(n->_node); } 1498 1499 static bool classof(const EmptyHNode *) { return true; } 1500 }; 1501 1502 class ScalarHNode : public HNode { 1503 public: 1504 ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { } 1505 1506 StringRef value() const { return _value; } 1507 1508 static bool classof(const HNode *n) { 1509 return ScalarNode::classof(n->_node) || 1510 BlockScalarNode::classof(n->_node); 1511 } 1512 1513 static bool classof(const ScalarHNode *) { return true; } 1514 1515 protected: 1516 StringRef _value; 1517 }; 1518 1519 class MapHNode : public HNode { 1520 public: 1521 MapHNode(Node *n) : HNode(n) { } 1522 1523 static bool classof(const HNode *n) { 1524 return MappingNode::classof(n->_node); 1525 } 1526 1527 static bool classof(const MapHNode *) { return true; } 1528 1529 using NameToNodeAndLoc = StringMap<std::pair<HNode *, SMRange>>; 1530 1531 NameToNodeAndLoc Mapping; 1532 SmallVector<std::string, 6> ValidKeys; 1533 }; 1534 1535 class SequenceHNode : public HNode { 1536 public: 1537 SequenceHNode(Node *n) : HNode(n) { } 1538 1539 static bool classof(const HNode *n) { 1540 return SequenceNode::classof(n->_node); 1541 } 1542 1543 static bool classof(const SequenceHNode *) { return true; } 1544 1545 std::vector<HNode *> Entries; 1546 }; 1547 1548 Input::HNode *createHNodes(Node *node); 1549 void setError(HNode *hnode, const Twine &message); 1550 void setError(Node *node, const Twine &message); 1551 void setError(const SMRange &Range, const Twine &message); 1552 1553 void reportWarning(HNode *hnode, const Twine &message); 1554 void reportWarning(Node *hnode, const Twine &message); 1555 void reportWarning(const SMRange &Range, const Twine &message); 1556 1557 /// Release memory used by HNodes. 1558 void releaseHNodeBuffers(); 1559 1560 public: 1561 // These are only used by operator>>. They could be private 1562 // if those templated things could be made friends. 1563 bool setCurrentDocument(); 1564 bool nextDocument(); 1565 1566 /// Returns the current node that's being parsed by the YAML Parser. 1567 const Node *getCurrentNode() const; 1568 1569 void setAllowUnknownKeys(bool Allow) override; 1570 1571 private: 1572 SourceMgr SrcMgr; // must be before Strm 1573 std::unique_ptr<llvm::yaml::Stream> Strm; 1574 HNode *TopNode = nullptr; 1575 std::error_code EC; 1576 BumpPtrAllocator StringAllocator; 1577 SpecificBumpPtrAllocator<EmptyHNode> EmptyHNodeAllocator; 1578 SpecificBumpPtrAllocator<ScalarHNode> ScalarHNodeAllocator; 1579 SpecificBumpPtrAllocator<MapHNode> MapHNodeAllocator; 1580 SpecificBumpPtrAllocator<SequenceHNode> SequenceHNodeAllocator; 1581 document_iterator DocIterator; 1582 llvm::BitVector BitValuesUsed; 1583 HNode *CurrentNode = nullptr; 1584 bool ScalarMatchFound = false; 1585 bool AllowUnknownKeys = false; 1586 }; 1587 1588 /// 1589 /// The Output class is used to generate a yaml document from in-memory structs 1590 /// and vectors. 1591 /// 1592 class Output : public IO { 1593 public: 1594 Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70); 1595 ~Output() override; 1596 1597 /// Set whether or not to output optional values which are equal 1598 /// to the default value. By default, when outputting if you attempt 1599 /// to write a value that is equal to the default, the value gets ignored. 1600 /// Sometimes, it is useful to be able to see these in the resulting YAML 1601 /// anyway. 1602 void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; } 1603 1604 bool outputting() const override; 1605 bool mapTag(StringRef, bool) override; 1606 void beginMapping() override; 1607 void endMapping() override; 1608 bool preflightKey(const char *key, bool, bool, bool &, void *&) override; 1609 void postflightKey(void *) override; 1610 std::vector<StringRef> keys() override; 1611 void beginFlowMapping() override; 1612 void endFlowMapping() override; 1613 unsigned beginSequence() override; 1614 void endSequence() override; 1615 bool preflightElement(unsigned, void *&) override; 1616 void postflightElement(void *) override; 1617 unsigned beginFlowSequence() override; 1618 bool preflightFlowElement(unsigned, void *&) override; 1619 void postflightFlowElement(void *) override; 1620 void endFlowSequence() override; 1621 void beginEnumScalar() override; 1622 bool matchEnumScalar(const char*, bool) override; 1623 bool matchEnumFallback() override; 1624 void endEnumScalar() override; 1625 bool beginBitSetScalar(bool &) override; 1626 bool bitSetMatch(const char *, bool ) override; 1627 void endBitSetScalar() override; 1628 void scalarString(StringRef &, QuotingType) override; 1629 void blockScalarString(StringRef &) override; 1630 void scalarTag(std::string &) override; 1631 NodeKind getNodeKind() override; 1632 void setError(const Twine &message) override; 1633 bool canElideEmptySequence() override; 1634 1635 // These are only used by operator<<. They could be private 1636 // if that templated operator could be made a friend. 1637 void beginDocuments(); 1638 bool preflightDocument(unsigned); 1639 void postflightDocument(); 1640 void endDocuments(); 1641 1642 private: 1643 void output(StringRef s); 1644 void output(StringRef, QuotingType); 1645 void outputUpToEndOfLine(StringRef s); 1646 void newLineCheck(bool EmptySequence = false); 1647 void outputNewLine(); 1648 void paddedKey(StringRef key); 1649 void flowKey(StringRef Key); 1650 1651 enum InState { 1652 inSeqFirstElement, 1653 inSeqOtherElement, 1654 inFlowSeqFirstElement, 1655 inFlowSeqOtherElement, 1656 inMapFirstKey, 1657 inMapOtherKey, 1658 inFlowMapFirstKey, 1659 inFlowMapOtherKey 1660 }; 1661 1662 static bool inSeqAnyElement(InState State); 1663 static bool inFlowSeqAnyElement(InState State); 1664 static bool inMapAnyKey(InState State); 1665 static bool inFlowMapAnyKey(InState State); 1666 1667 raw_ostream &Out; 1668 int WrapColumn; 1669 SmallVector<InState, 8> StateStack; 1670 int Column = 0; 1671 int ColumnAtFlowStart = 0; 1672 int ColumnAtMapFlowStart = 0; 1673 bool NeedBitValueComma = false; 1674 bool NeedFlowSequenceComma = false; 1675 bool EnumerationMatchFound = false; 1676 bool WriteDefaultValues = false; 1677 StringRef Padding; 1678 StringRef PaddingBeforeContainer; 1679 }; 1680 1681 template <typename T, typename Context> 1682 void IO::processKeyWithDefault(const char *Key, std::optional<T> &Val, 1683 const std::optional<T> &DefaultValue, 1684 bool Required, Context &Ctx) { 1685 assert(!DefaultValue && "std::optional<T> shouldn't have a value!"); 1686 void *SaveInfo; 1687 bool UseDefault = true; 1688 const bool sameAsDefault = outputting() && !Val; 1689 if (!outputting() && !Val) 1690 Val = T(); 1691 if (Val && 1692 this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) { 1693 1694 // When reading an std::optional<X> key from a YAML description, we allow 1695 // the special "<none>" value, which can be used to specify that no value 1696 // was requested, i.e. the DefaultValue will be assigned. The DefaultValue 1697 // is usually None. 1698 bool IsNone = false; 1699 if (!outputting()) 1700 if (const auto *Node = 1701 dyn_cast<ScalarNode>(((Input *)this)->getCurrentNode())) 1702 // We use rtrim to ignore possible white spaces that might exist when a 1703 // comment is present on the same line. 1704 IsNone = Node->getRawValue().rtrim(' ') == "<none>"; 1705 1706 if (IsNone) 1707 Val = DefaultValue; 1708 else 1709 yamlize(*this, *Val, Required, Ctx); 1710 this->postflightKey(SaveInfo); 1711 } else { 1712 if (UseDefault) 1713 Val = DefaultValue; 1714 } 1715 } 1716 1717 /// YAML I/O does conversion based on types. But often native data types 1718 /// are just a typedef of built in intergral types (e.g. int). But the C++ 1719 /// type matching system sees through the typedef and all the typedefed types 1720 /// look like a built in type. This will cause the generic YAML I/O conversion 1721 /// to be used. To provide better control over the YAML conversion, you can 1722 /// use this macro instead of typedef. It will create a class with one field 1723 /// and automatic conversion operators to and from the base type. 1724 /// Based on BOOST_STRONG_TYPEDEF 1725 #define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ 1726 struct _type { \ 1727 _type() = default; \ 1728 _type(const _base v) : value(v) {} \ 1729 _type(const _type &v) = default; \ 1730 _type &operator=(const _type &rhs) = default; \ 1731 _type &operator=(const _base &rhs) { value = rhs; return *this; } \ 1732 operator const _base & () const { return value; } \ 1733 bool operator==(const _type &rhs) const { return value == rhs.value; } \ 1734 bool operator==(const _base &rhs) const { return value == rhs; } \ 1735 bool operator<(const _type &rhs) const { return value < rhs.value; } \ 1736 _base value; \ 1737 using BaseType = _base; \ 1738 }; 1739 1740 /// 1741 /// Use these types instead of uintXX_t in any mapping to have 1742 /// its yaml output formatted as hexadecimal. 1743 /// 1744 LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) 1745 LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) 1746 LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) 1747 LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) 1748 1749 template<> 1750 struct ScalarTraits<Hex8> { 1751 static void output(const Hex8 &, void *, raw_ostream &); 1752 static StringRef input(StringRef, void *, Hex8 &); 1753 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1754 }; 1755 1756 template<> 1757 struct ScalarTraits<Hex16> { 1758 static void output(const Hex16 &, void *, raw_ostream &); 1759 static StringRef input(StringRef, void *, Hex16 &); 1760 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1761 }; 1762 1763 template<> 1764 struct ScalarTraits<Hex32> { 1765 static void output(const Hex32 &, void *, raw_ostream &); 1766 static StringRef input(StringRef, void *, Hex32 &); 1767 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1768 }; 1769 1770 template<> 1771 struct ScalarTraits<Hex64> { 1772 static void output(const Hex64 &, void *, raw_ostream &); 1773 static StringRef input(StringRef, void *, Hex64 &); 1774 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1775 }; 1776 1777 template <> struct ScalarTraits<VersionTuple> { 1778 static void output(const VersionTuple &Value, void *, llvm::raw_ostream &Out); 1779 static StringRef input(StringRef, void *, VersionTuple &); 1780 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1781 }; 1782 1783 // Define non-member operator>> so that Input can stream in a document list. 1784 template <typename T> 1785 inline std::enable_if_t<has_DocumentListTraits<T>::value, Input &> 1786 operator>>(Input &yin, T &docList) { 1787 int i = 0; 1788 EmptyContext Ctx; 1789 while ( yin.setCurrentDocument() ) { 1790 yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx); 1791 if ( yin.error() ) 1792 return yin; 1793 yin.nextDocument(); 1794 ++i; 1795 } 1796 return yin; 1797 } 1798 1799 // Define non-member operator>> so that Input can stream in a map as a document. 1800 template <typename T> 1801 inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Input &> 1802 operator>>(Input &yin, T &docMap) { 1803 EmptyContext Ctx; 1804 yin.setCurrentDocument(); 1805 yamlize(yin, docMap, true, Ctx); 1806 return yin; 1807 } 1808 1809 // Define non-member operator>> so that Input can stream in a sequence as 1810 // a document. 1811 template <typename T> 1812 inline std::enable_if_t<has_SequenceTraits<T>::value, Input &> 1813 operator>>(Input &yin, T &docSeq) { 1814 EmptyContext Ctx; 1815 if (yin.setCurrentDocument()) 1816 yamlize(yin, docSeq, true, Ctx); 1817 return yin; 1818 } 1819 1820 // Define non-member operator>> so that Input can stream in a block scalar. 1821 template <typename T> 1822 inline std::enable_if_t<has_BlockScalarTraits<T>::value, Input &> 1823 operator>>(Input &In, T &Val) { 1824 EmptyContext Ctx; 1825 if (In.setCurrentDocument()) 1826 yamlize(In, Val, true, Ctx); 1827 return In; 1828 } 1829 1830 // Define non-member operator>> so that Input can stream in a string map. 1831 template <typename T> 1832 inline std::enable_if_t<has_CustomMappingTraits<T>::value, Input &> 1833 operator>>(Input &In, T &Val) { 1834 EmptyContext Ctx; 1835 if (In.setCurrentDocument()) 1836 yamlize(In, Val, true, Ctx); 1837 return In; 1838 } 1839 1840 // Define non-member operator>> so that Input can stream in a polymorphic type. 1841 template <typename T> 1842 inline std::enable_if_t<has_PolymorphicTraits<T>::value, Input &> 1843 operator>>(Input &In, T &Val) { 1844 EmptyContext Ctx; 1845 if (In.setCurrentDocument()) 1846 yamlize(In, Val, true, Ctx); 1847 return In; 1848 } 1849 1850 // Provide better error message about types missing a trait specialization 1851 template <typename T> 1852 inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Input &> 1853 operator>>(Input &yin, T &docSeq) { 1854 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1855 return yin; 1856 } 1857 1858 // Define non-member operator<< so that Output can stream out document list. 1859 template <typename T> 1860 inline std::enable_if_t<has_DocumentListTraits<T>::value, Output &> 1861 operator<<(Output &yout, T &docList) { 1862 EmptyContext Ctx; 1863 yout.beginDocuments(); 1864 const size_t count = DocumentListTraits<T>::size(yout, docList); 1865 for(size_t i=0; i < count; ++i) { 1866 if ( yout.preflightDocument(i) ) { 1867 yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true, 1868 Ctx); 1869 yout.postflightDocument(); 1870 } 1871 } 1872 yout.endDocuments(); 1873 return yout; 1874 } 1875 1876 // Define non-member operator<< so that Output can stream out a map. 1877 template <typename T> 1878 inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Output &> 1879 operator<<(Output &yout, T &map) { 1880 EmptyContext Ctx; 1881 yout.beginDocuments(); 1882 if ( yout.preflightDocument(0) ) { 1883 yamlize(yout, map, true, Ctx); 1884 yout.postflightDocument(); 1885 } 1886 yout.endDocuments(); 1887 return yout; 1888 } 1889 1890 // Define non-member operator<< so that Output can stream out a sequence. 1891 template <typename T> 1892 inline std::enable_if_t<has_SequenceTraits<T>::value, Output &> 1893 operator<<(Output &yout, T &seq) { 1894 EmptyContext Ctx; 1895 yout.beginDocuments(); 1896 if ( yout.preflightDocument(0) ) { 1897 yamlize(yout, seq, true, Ctx); 1898 yout.postflightDocument(); 1899 } 1900 yout.endDocuments(); 1901 return yout; 1902 } 1903 1904 // Define non-member operator<< so that Output can stream out a block scalar. 1905 template <typename T> 1906 inline std::enable_if_t<has_BlockScalarTraits<T>::value, Output &> 1907 operator<<(Output &Out, T &Val) { 1908 EmptyContext Ctx; 1909 Out.beginDocuments(); 1910 if (Out.preflightDocument(0)) { 1911 yamlize(Out, Val, true, Ctx); 1912 Out.postflightDocument(); 1913 } 1914 Out.endDocuments(); 1915 return Out; 1916 } 1917 1918 // Define non-member operator<< so that Output can stream out a string map. 1919 template <typename T> 1920 inline std::enable_if_t<has_CustomMappingTraits<T>::value, Output &> 1921 operator<<(Output &Out, T &Val) { 1922 EmptyContext Ctx; 1923 Out.beginDocuments(); 1924 if (Out.preflightDocument(0)) { 1925 yamlize(Out, Val, true, Ctx); 1926 Out.postflightDocument(); 1927 } 1928 Out.endDocuments(); 1929 return Out; 1930 } 1931 1932 // Define non-member operator<< so that Output can stream out a polymorphic 1933 // type. 1934 template <typename T> 1935 inline std::enable_if_t<has_PolymorphicTraits<T>::value, Output &> 1936 operator<<(Output &Out, T &Val) { 1937 EmptyContext Ctx; 1938 Out.beginDocuments(); 1939 if (Out.preflightDocument(0)) { 1940 // FIXME: The parser does not support explicit documents terminated with a 1941 // plain scalar; the end-marker is included as part of the scalar token. 1942 assert(PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && "plain scalar documents are not supported"); 1943 yamlize(Out, Val, true, Ctx); 1944 Out.postflightDocument(); 1945 } 1946 Out.endDocuments(); 1947 return Out; 1948 } 1949 1950 // Provide better error message about types missing a trait specialization 1951 template <typename T> 1952 inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Output &> 1953 operator<<(Output &yout, T &seq) { 1954 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1955 return yout; 1956 } 1957 1958 template <bool B> struct IsFlowSequenceBase {}; 1959 template <> struct IsFlowSequenceBase<true> { static const bool flow = true; }; 1960 1961 template <typename T, typename U = void> 1962 struct IsResizable : std::false_type {}; 1963 1964 template <typename T> 1965 struct IsResizable<T, std::void_t<decltype(std::declval<T>().resize(0))>> 1966 : public std::true_type {}; 1967 1968 template <typename T, bool B> struct IsResizableBase { 1969 using type = typename T::value_type; 1970 1971 static type &element(IO &io, T &seq, size_t index) { 1972 if (index >= seq.size()) 1973 seq.resize(index + 1); 1974 return seq[index]; 1975 } 1976 }; 1977 1978 template <typename T> struct IsResizableBase<T, false> { 1979 using type = typename T::value_type; 1980 1981 static type &element(IO &io, T &seq, size_t index) { 1982 if (index >= seq.size()) { 1983 io.setError(Twine("value sequence extends beyond static size (") + 1984 Twine(seq.size()) + ")"); 1985 return seq[0]; 1986 } 1987 return seq[index]; 1988 } 1989 }; 1990 1991 template <typename T, bool Flow> 1992 struct SequenceTraitsImpl 1993 : IsFlowSequenceBase<Flow>, IsResizableBase<T, IsResizable<T>::value> { 1994 static size_t size(IO &io, T &seq) { return seq.size(); } 1995 }; 1996 1997 // Simple helper to check an expression can be used as a bool-valued template 1998 // argument. 1999 template <bool> struct CheckIsBool { static const bool value = true; }; 2000 2001 // If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have 2002 // SequenceTraits that do the obvious thing. 2003 template <typename T> 2004 struct SequenceTraits< 2005 std::vector<T>, 2006 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 2007 : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {}; 2008 template <typename T, unsigned N> 2009 struct SequenceTraits< 2010 SmallVector<T, N>, 2011 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 2012 : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {}; 2013 template <typename T> 2014 struct SequenceTraits< 2015 SmallVectorImpl<T>, 2016 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 2017 : SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {}; 2018 template <typename T> 2019 struct SequenceTraits< 2020 MutableArrayRef<T>, 2021 std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>> 2022 : SequenceTraitsImpl<MutableArrayRef<T>, SequenceElementTraits<T>::flow> {}; 2023 2024 // Sequences of fundamental types use flow formatting. 2025 template <typename T> 2026 struct SequenceElementTraits<T, std::enable_if_t<std::is_fundamental_v<T>>> { 2027 static const bool flow = true; 2028 }; 2029 2030 // Sequences of strings use block formatting. 2031 template<> struct SequenceElementTraits<std::string> { 2032 static const bool flow = false; 2033 }; 2034 template<> struct SequenceElementTraits<StringRef> { 2035 static const bool flow = false; 2036 }; 2037 template<> struct SequenceElementTraits<std::pair<std::string, std::string>> { 2038 static const bool flow = false; 2039 }; 2040 2041 /// Implementation of CustomMappingTraits for std::map<std::string, T>. 2042 template <typename T> struct StdMapStringCustomMappingTraitsImpl { 2043 using map_type = std::map<std::string, T>; 2044 2045 static void inputOne(IO &io, StringRef key, map_type &v) { 2046 io.mapRequired(key.str().c_str(), v[std::string(key)]); 2047 } 2048 2049 static void output(IO &io, map_type &v) { 2050 for (auto &p : v) 2051 io.mapRequired(p.first.c_str(), p.second); 2052 } 2053 }; 2054 2055 } // end namespace yaml 2056 } // end namespace llvm 2057 2058 #define LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(TYPE, FLOW) \ 2059 namespace llvm { \ 2060 namespace yaml { \ 2061 static_assert( \ 2062 !std::is_fundamental_v<TYPE> && !std::is_same_v<TYPE, std::string> && \ 2063 !std::is_same_v<TYPE, llvm::StringRef>, \ 2064 "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control"); \ 2065 template <> struct SequenceElementTraits<TYPE> { \ 2066 static const bool flow = FLOW; \ 2067 }; \ 2068 } \ 2069 } 2070 2071 /// Utility for declaring that a std::vector of a particular type 2072 /// should be considered a YAML sequence. 2073 #define LLVM_YAML_IS_SEQUENCE_VECTOR(type) \ 2074 LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, false) 2075 2076 /// Utility for declaring that a std::vector of a particular type 2077 /// should be considered a YAML flow sequence. 2078 #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(type) \ 2079 LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, true) 2080 2081 #define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type) \ 2082 namespace llvm { \ 2083 namespace yaml { \ 2084 template <> struct MappingTraits<Type> { \ 2085 static void mapping(IO &IO, Type &Obj); \ 2086 }; \ 2087 } \ 2088 } 2089 2090 #define LLVM_YAML_DECLARE_ENUM_TRAITS(Type) \ 2091 namespace llvm { \ 2092 namespace yaml { \ 2093 template <> struct ScalarEnumerationTraits<Type> { \ 2094 static void enumeration(IO &io, Type &Value); \ 2095 }; \ 2096 } \ 2097 } 2098 2099 #define LLVM_YAML_DECLARE_BITSET_TRAITS(Type) \ 2100 namespace llvm { \ 2101 namespace yaml { \ 2102 template <> struct ScalarBitSetTraits<Type> { \ 2103 static void bitset(IO &IO, Type &Options); \ 2104 }; \ 2105 } \ 2106 } 2107 2108 #define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote) \ 2109 namespace llvm { \ 2110 namespace yaml { \ 2111 template <> struct ScalarTraits<Type> { \ 2112 static void output(const Type &Value, void *ctx, raw_ostream &Out); \ 2113 static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \ 2114 static QuotingType mustQuote(StringRef) { return MustQuote; } \ 2115 }; \ 2116 } \ 2117 } 2118 2119 /// Utility for declaring that a std::vector of a particular type 2120 /// should be considered a YAML document list. 2121 #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ 2122 namespace llvm { \ 2123 namespace yaml { \ 2124 template <unsigned N> \ 2125 struct DocumentListTraits<SmallVector<_type, N>> \ 2126 : public SequenceTraitsImpl<SmallVector<_type, N>, false> {}; \ 2127 template <> \ 2128 struct DocumentListTraits<std::vector<_type>> \ 2129 : public SequenceTraitsImpl<std::vector<_type>, false> {}; \ 2130 } \ 2131 } 2132 2133 /// Utility for declaring that std::map<std::string, _type> should be considered 2134 /// a YAML map. 2135 #define LLVM_YAML_IS_STRING_MAP(_type) \ 2136 namespace llvm { \ 2137 namespace yaml { \ 2138 template <> \ 2139 struct CustomMappingTraits<std::map<std::string, _type>> \ 2140 : public StdMapStringCustomMappingTraitsImpl<_type> {}; \ 2141 } \ 2142 } 2143 2144 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64) 2145 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex32) 2146 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex16) 2147 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex8) 2148 2149 #endif // LLVM_SUPPORT_YAMLTRAITS_H 2150