1 //===- llvm/Support/YAMLTraits.h --------------------------------*- C++ -*-===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef LLVM_SUPPORT_YAMLTRAITS_H 11 #define LLVM_SUPPORT_YAMLTRAITS_H 12 13 14 #include "llvm/ADT/DenseMap.h" 15 #include "llvm/ADT/DenseMapInfo.h" 16 #include "llvm/ADT/Optional.h" 17 #include "llvm/ADT/SmallVector.h" 18 #include "llvm/ADT/StringMap.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/ADT/StringSwitch.h" 21 #include "llvm/ADT/Twine.h" 22 #include "llvm/Support/Compiler.h" 23 #include "llvm/Support/Regex.h" 24 #include "llvm/Support/SourceMgr.h" 25 #include "llvm/Support/YAMLParser.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include <system_error> 28 29 namespace llvm { 30 namespace yaml { 31 32 33 /// This class should be specialized by any type that needs to be converted 34 /// to/from a YAML mapping. For example: 35 /// 36 /// struct MappingTraits<MyStruct> { 37 /// static void mapping(IO &io, MyStruct &s) { 38 /// io.mapRequired("name", s.name); 39 /// io.mapRequired("size", s.size); 40 /// io.mapOptional("age", s.age); 41 /// } 42 /// }; 43 template<class T> 44 struct MappingTraits { 45 // Must provide: 46 // static void mapping(IO &io, T &fields); 47 // Optionally may provide: 48 // static StringRef validate(IO &io, T &fields); 49 }; 50 51 52 /// This class should be specialized by any integral type that converts 53 /// to/from a YAML scalar where there is a one-to-one mapping between 54 /// in-memory values and a string in YAML. For example: 55 /// 56 /// struct ScalarEnumerationTraits<Colors> { 57 /// static void enumeration(IO &io, Colors &value) { 58 /// io.enumCase(value, "red", cRed); 59 /// io.enumCase(value, "blue", cBlue); 60 /// io.enumCase(value, "green", cGreen); 61 /// } 62 /// }; 63 template<typename T> 64 struct ScalarEnumerationTraits { 65 // Must provide: 66 // static void enumeration(IO &io, T &value); 67 }; 68 69 70 /// This class should be specialized by any integer type that is a union 71 /// of bit values and the YAML representation is a flow sequence of 72 /// strings. For example: 73 /// 74 /// struct ScalarBitSetTraits<MyFlags> { 75 /// static void bitset(IO &io, MyFlags &value) { 76 /// io.bitSetCase(value, "big", flagBig); 77 /// io.bitSetCase(value, "flat", flagFlat); 78 /// io.bitSetCase(value, "round", flagRound); 79 /// } 80 /// }; 81 template<typename T> 82 struct ScalarBitSetTraits { 83 // Must provide: 84 // static void bitset(IO &io, T &value); 85 }; 86 87 88 /// This class should be specialized by type that requires custom conversion 89 /// to/from a yaml scalar. For example: 90 /// 91 /// template<> 92 /// struct ScalarTraits<MyType> { 93 /// static void output(const MyType &val, void*, llvm::raw_ostream &out) { 94 /// // stream out custom formatting 95 /// out << llvm::format("%x", val); 96 /// } 97 /// static StringRef input(StringRef scalar, void*, MyType &value) { 98 /// // parse scalar and set `value` 99 /// // return empty string on success, or error string 100 /// return StringRef(); 101 /// } 102 /// static bool mustQuote(StringRef) { return true; } 103 /// }; 104 template<typename T> 105 struct ScalarTraits { 106 // Must provide: 107 // 108 // Function to write the value as a string: 109 //static void output(const T &value, void *ctxt, llvm::raw_ostream &out); 110 // 111 // Function to convert a string to a value. Returns the empty 112 // StringRef on success or an error string if string is malformed: 113 //static StringRef input(StringRef scalar, void *ctxt, T &value); 114 // 115 // Function to determine if the value should be quoted. 116 //static bool mustQuote(StringRef); 117 }; 118 119 120 /// This class should be specialized by any type that needs to be converted 121 /// to/from a YAML sequence. For example: 122 /// 123 /// template<> 124 /// struct SequenceTraits< std::vector<MyType> > { 125 /// static size_t size(IO &io, std::vector<MyType> &seq) { 126 /// return seq.size(); 127 /// } 128 /// static MyType& element(IO &, std::vector<MyType> &seq, size_t index) { 129 /// if ( index >= seq.size() ) 130 /// seq.resize(index+1); 131 /// return seq[index]; 132 /// } 133 /// }; 134 template<typename T> 135 struct SequenceTraits { 136 // Must provide: 137 // static size_t size(IO &io, T &seq); 138 // static T::value_type& element(IO &io, T &seq, size_t index); 139 // 140 // The following is option and will cause generated YAML to use 141 // a flow sequence (e.g. [a,b,c]). 142 // static const bool flow = true; 143 }; 144 145 146 /// This class should be specialized by any type that needs to be converted 147 /// to/from a list of YAML documents. 148 template<typename T> 149 struct DocumentListTraits { 150 // Must provide: 151 // static size_t size(IO &io, T &seq); 152 // static T::value_type& element(IO &io, T &seq, size_t index); 153 }; 154 155 156 // Only used by compiler if both template types are the same 157 template <typename T, T> 158 struct SameType; 159 160 // Only used for better diagnostics of missing traits 161 template <typename T> 162 struct MissingTrait; 163 164 165 166 // Test if ScalarEnumerationTraits<T> is defined on type T. 167 template <class T> 168 struct has_ScalarEnumerationTraits 169 { 170 typedef void (*Signature_enumeration)(class IO&, T&); 171 172 template <typename U> 173 static char test(SameType<Signature_enumeration, &U::enumeration>*); 174 175 template <typename U> 176 static double test(...); 177 178 public: 179 static bool const value = 180 (sizeof(test<ScalarEnumerationTraits<T> >(nullptr)) == 1); 181 }; 182 183 184 // Test if ScalarBitSetTraits<T> is defined on type T. 185 template <class T> 186 struct has_ScalarBitSetTraits 187 { 188 typedef void (*Signature_bitset)(class IO&, T&); 189 190 template <typename U> 191 static char test(SameType<Signature_bitset, &U::bitset>*); 192 193 template <typename U> 194 static double test(...); 195 196 public: 197 static bool const value = (sizeof(test<ScalarBitSetTraits<T> >(nullptr)) == 1); 198 }; 199 200 201 // Test if ScalarTraits<T> is defined on type T. 202 template <class T> 203 struct has_ScalarTraits 204 { 205 typedef StringRef (*Signature_input)(StringRef, void*, T&); 206 typedef void (*Signature_output)(const T&, void*, llvm::raw_ostream&); 207 typedef bool (*Signature_mustQuote)(StringRef); 208 209 template <typename U> 210 static char test(SameType<Signature_input, &U::input> *, 211 SameType<Signature_output, &U::output> *, 212 SameType<Signature_mustQuote, &U::mustQuote> *); 213 214 template <typename U> 215 static double test(...); 216 217 public: 218 static bool const value = 219 (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1); 220 }; 221 222 223 // Test if MappingTraits<T> is defined on type T. 224 template <class T> 225 struct has_MappingTraits 226 { 227 typedef void (*Signature_mapping)(class IO&, T&); 228 229 template <typename U> 230 static char test(SameType<Signature_mapping, &U::mapping>*); 231 232 template <typename U> 233 static double test(...); 234 235 public: 236 static bool const value = (sizeof(test<MappingTraits<T> >(nullptr)) == 1); 237 }; 238 239 // Test if MappingTraits<T>::validate() is defined on type T. 240 template <class T> 241 struct has_MappingValidateTraits 242 { 243 typedef StringRef (*Signature_validate)(class IO&, T&); 244 245 template <typename U> 246 static char test(SameType<Signature_validate, &U::validate>*); 247 248 template <typename U> 249 static double test(...); 250 251 public: 252 static bool const value = (sizeof(test<MappingTraits<T> >(nullptr)) == 1); 253 }; 254 255 256 257 // Test if SequenceTraits<T> is defined on type T. 258 template <class T> 259 struct has_SequenceMethodTraits 260 { 261 typedef size_t (*Signature_size)(class IO&, T&); 262 263 template <typename U> 264 static char test(SameType<Signature_size, &U::size>*); 265 266 template <typename U> 267 static double test(...); 268 269 public: 270 static bool const value = (sizeof(test<SequenceTraits<T> >(nullptr)) == 1); 271 }; 272 273 274 // has_FlowTraits<int> will cause an error with some compilers because 275 // it subclasses int. Using this wrapper only instantiates the 276 // real has_FlowTraits only if the template type is a class. 277 template <typename T, bool Enabled = std::is_class<T>::value> 278 class has_FlowTraits 279 { 280 public: 281 static const bool value = false; 282 }; 283 284 // Some older gcc compilers don't support straight forward tests 285 // for members, so test for ambiguity cause by the base and derived 286 // classes both defining the member. 287 template <class T> 288 struct has_FlowTraits<T, true> 289 { 290 struct Fallback { bool flow; }; 291 struct Derived : T, Fallback { }; 292 293 template<typename C> 294 static char (&f(SameType<bool Fallback::*, &C::flow>*))[1]; 295 296 template<typename C> 297 static char (&f(...))[2]; 298 299 public: 300 static bool const value = sizeof(f<Derived>(nullptr)) == 2; 301 }; 302 303 304 305 // Test if SequenceTraits<T> is defined on type T 306 template<typename T> 307 struct has_SequenceTraits : public std::integral_constant<bool, 308 has_SequenceMethodTraits<T>::value > { }; 309 310 311 // Test if DocumentListTraits<T> is defined on type T 312 template <class T> 313 struct has_DocumentListTraits 314 { 315 typedef size_t (*Signature_size)(class IO&, T&); 316 317 template <typename U> 318 static char test(SameType<Signature_size, &U::size>*); 319 320 template <typename U> 321 static double test(...); 322 323 public: 324 static bool const value = (sizeof(test<DocumentListTraits<T> >(nullptr))==1); 325 }; 326 327 inline bool isNumber(StringRef S) { 328 static const char OctalChars[] = "01234567"; 329 if (S.startswith("0") && 330 S.drop_front().find_first_not_of(OctalChars) == StringRef::npos) 331 return true; 332 333 if (S.startswith("0o") && 334 S.drop_front(2).find_first_not_of(OctalChars) == StringRef::npos) 335 return true; 336 337 static const char HexChars[] = "0123456789abcdefABCDEF"; 338 if (S.startswith("0x") && 339 S.drop_front(2).find_first_not_of(HexChars) == StringRef::npos) 340 return true; 341 342 static const char DecChars[] = "0123456789"; 343 if (S.find_first_not_of(DecChars) == StringRef::npos) 344 return true; 345 346 if (S.equals(".inf") || S.equals(".Inf") || S.equals(".INF")) 347 return true; 348 349 Regex FloatMatcher("^(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?$"); 350 if (FloatMatcher.match(S)) 351 return true; 352 353 return false; 354 } 355 356 inline bool isNumeric(StringRef S) { 357 if ((S.front() == '-' || S.front() == '+') && isNumber(S.drop_front())) 358 return true; 359 360 if (isNumber(S)) 361 return true; 362 363 if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN")) 364 return true; 365 366 return false; 367 } 368 369 inline bool isNull(StringRef S) { 370 return S.equals("null") || S.equals("Null") || S.equals("NULL") || 371 S.equals("~"); 372 } 373 374 inline bool isBool(StringRef S) { 375 return S.equals("true") || S.equals("True") || S.equals("TRUE") || 376 S.equals("false") || S.equals("False") || S.equals("FALSE"); 377 } 378 379 inline bool needsQuotes(StringRef S) { 380 if (S.empty()) 381 return true; 382 if (isspace(S.front()) || isspace(S.back())) 383 return true; 384 if (S.front() == ',') 385 return true; 386 387 static const char ScalarSafeChars[] = 388 "abcdefghijklmnopqrstuvwxyz" 389 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t"; 390 if (S.find_first_not_of(ScalarSafeChars) != StringRef::npos) 391 return true; 392 393 if (isNull(S)) 394 return true; 395 if (isBool(S)) 396 return true; 397 if (isNumeric(S)) 398 return true; 399 400 return false; 401 } 402 403 404 template<typename T> 405 struct missingTraits : public std::integral_constant<bool, 406 !has_ScalarEnumerationTraits<T>::value 407 && !has_ScalarBitSetTraits<T>::value 408 && !has_ScalarTraits<T>::value 409 && !has_MappingTraits<T>::value 410 && !has_SequenceTraits<T>::value 411 && !has_DocumentListTraits<T>::value > {}; 412 413 template<typename T> 414 struct validatedMappingTraits : public std::integral_constant<bool, 415 has_MappingTraits<T>::value 416 && has_MappingValidateTraits<T>::value> {}; 417 418 template<typename T> 419 struct unvalidatedMappingTraits : public std::integral_constant<bool, 420 has_MappingTraits<T>::value 421 && !has_MappingValidateTraits<T>::value> {}; 422 // Base class for Input and Output. 423 class IO { 424 public: 425 426 IO(void *Ctxt=nullptr); 427 virtual ~IO(); 428 429 virtual bool outputting() = 0; 430 431 virtual unsigned beginSequence() = 0; 432 virtual bool preflightElement(unsigned, void *&) = 0; 433 virtual void postflightElement(void*) = 0; 434 virtual void endSequence() = 0; 435 virtual bool canElideEmptySequence() = 0; 436 437 virtual unsigned beginFlowSequence() = 0; 438 virtual bool preflightFlowElement(unsigned, void *&) = 0; 439 virtual void postflightFlowElement(void*) = 0; 440 virtual void endFlowSequence() = 0; 441 442 virtual bool mapTag(StringRef Tag, bool Default=false) = 0; 443 virtual void beginMapping() = 0; 444 virtual void endMapping() = 0; 445 virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0; 446 virtual void postflightKey(void*) = 0; 447 448 virtual void beginEnumScalar() = 0; 449 virtual bool matchEnumScalar(const char*, bool) = 0; 450 virtual bool matchEnumFallback() = 0; 451 virtual void endEnumScalar() = 0; 452 453 virtual bool beginBitSetScalar(bool &) = 0; 454 virtual bool bitSetMatch(const char*, bool) = 0; 455 virtual void endBitSetScalar() = 0; 456 457 virtual void scalarString(StringRef &, bool) = 0; 458 459 virtual void setError(const Twine &) = 0; 460 461 template <typename T> 462 void enumCase(T &Val, const char* Str, const T ConstVal) { 463 if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) { 464 Val = ConstVal; 465 } 466 } 467 468 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 469 template <typename T> 470 void enumCase(T &Val, const char* Str, const uint32_t ConstVal) { 471 if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) { 472 Val = ConstVal; 473 } 474 } 475 476 template <typename FBT, typename T> 477 void enumFallback(T &Val) { 478 if ( matchEnumFallback() ) { 479 // FIXME: Force integral conversion to allow strong typedefs to convert. 480 FBT Res = (uint64_t)Val; 481 yamlize(*this, Res, true); 482 Val = (uint64_t)Res; 483 } 484 } 485 486 template <typename T> 487 void bitSetCase(T &Val, const char* Str, const T ConstVal) { 488 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 489 Val = Val | ConstVal; 490 } 491 } 492 493 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 494 template <typename T> 495 void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) { 496 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 497 Val = Val | ConstVal; 498 } 499 } 500 501 template <typename T> 502 void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) { 503 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 504 Val = Val | ConstVal; 505 } 506 507 template <typename T> 508 void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal, 509 uint32_t Mask) { 510 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 511 Val = Val | ConstVal; 512 } 513 514 void *getContext(); 515 void setContext(void *); 516 517 template <typename T> 518 void mapRequired(const char* Key, T& Val) { 519 this->processKey(Key, Val, true); 520 } 521 522 template <typename T> 523 typename std::enable_if<has_SequenceTraits<T>::value,void>::type 524 mapOptional(const char* Key, T& Val) { 525 // omit key/value instead of outputting empty sequence 526 if ( this->canElideEmptySequence() && !(Val.begin() != Val.end()) ) 527 return; 528 this->processKey(Key, Val, false); 529 } 530 531 template <typename T> 532 void mapOptional(const char* Key, Optional<T> &Val) { 533 processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false); 534 } 535 536 template <typename T> 537 typename std::enable_if<!has_SequenceTraits<T>::value,void>::type 538 mapOptional(const char* Key, T& Val) { 539 this->processKey(Key, Val, false); 540 } 541 542 template <typename T> 543 void mapOptional(const char* Key, T& Val, const T& Default) { 544 this->processKeyWithDefault(Key, Val, Default, false); 545 } 546 547 private: 548 template <typename T> 549 void processKeyWithDefault(const char *Key, Optional<T> &Val, 550 const Optional<T> &DefaultValue, bool Required) { 551 assert(DefaultValue.hasValue() == false && 552 "Optional<T> shouldn't have a value!"); 553 void *SaveInfo; 554 bool UseDefault; 555 const bool sameAsDefault = outputting() && !Val.hasValue(); 556 if (!outputting() && !Val.hasValue()) 557 Val = T(); 558 if (this->preflightKey(Key, Required, sameAsDefault, UseDefault, 559 SaveInfo)) { 560 yamlize(*this, Val.getValue(), Required); 561 this->postflightKey(SaveInfo); 562 } else { 563 if (UseDefault) 564 Val = DefaultValue; 565 } 566 } 567 568 template <typename T> 569 void processKeyWithDefault(const char *Key, T &Val, const T& DefaultValue, 570 bool Required) { 571 void *SaveInfo; 572 bool UseDefault; 573 const bool sameAsDefault = outputting() && Val == DefaultValue; 574 if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault, 575 SaveInfo) ) { 576 yamlize(*this, Val, Required); 577 this->postflightKey(SaveInfo); 578 } 579 else { 580 if ( UseDefault ) 581 Val = DefaultValue; 582 } 583 } 584 585 template <typename T> 586 void processKey(const char *Key, T &Val, bool Required) { 587 void *SaveInfo; 588 bool UseDefault; 589 if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) { 590 yamlize(*this, Val, Required); 591 this->postflightKey(SaveInfo); 592 } 593 } 594 595 private: 596 void *Ctxt; 597 }; 598 599 600 601 template<typename T> 602 typename std::enable_if<has_ScalarEnumerationTraits<T>::value,void>::type 603 yamlize(IO &io, T &Val, bool) { 604 io.beginEnumScalar(); 605 ScalarEnumerationTraits<T>::enumeration(io, Val); 606 io.endEnumScalar(); 607 } 608 609 template<typename T> 610 typename std::enable_if<has_ScalarBitSetTraits<T>::value,void>::type 611 yamlize(IO &io, T &Val, bool) { 612 bool DoClear; 613 if ( io.beginBitSetScalar(DoClear) ) { 614 if ( DoClear ) 615 Val = static_cast<T>(0); 616 ScalarBitSetTraits<T>::bitset(io, Val); 617 io.endBitSetScalar(); 618 } 619 } 620 621 622 template<typename T> 623 typename std::enable_if<has_ScalarTraits<T>::value,void>::type 624 yamlize(IO &io, T &Val, bool) { 625 if ( io.outputting() ) { 626 std::string Storage; 627 llvm::raw_string_ostream Buffer(Storage); 628 ScalarTraits<T>::output(Val, io.getContext(), Buffer); 629 StringRef Str = Buffer.str(); 630 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); 631 } 632 else { 633 StringRef Str; 634 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); 635 StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val); 636 if ( !Result.empty() ) { 637 io.setError(llvm::Twine(Result)); 638 } 639 } 640 } 641 642 643 template<typename T> 644 typename std::enable_if<validatedMappingTraits<T>::value, void>::type 645 yamlize(IO &io, T &Val, bool) { 646 io.beginMapping(); 647 if (io.outputting()) { 648 StringRef Err = MappingTraits<T>::validate(io, Val); 649 if (!Err.empty()) { 650 llvm::errs() << Err << "\n"; 651 assert(Err.empty() && "invalid struct trying to be written as yaml"); 652 } 653 } 654 MappingTraits<T>::mapping(io, Val); 655 if (!io.outputting()) { 656 StringRef Err = MappingTraits<T>::validate(io, Val); 657 if (!Err.empty()) 658 io.setError(Err); 659 } 660 io.endMapping(); 661 } 662 663 template<typename T> 664 typename std::enable_if<unvalidatedMappingTraits<T>::value, void>::type 665 yamlize(IO &io, T &Val, bool) { 666 io.beginMapping(); 667 MappingTraits<T>::mapping(io, Val); 668 io.endMapping(); 669 } 670 671 template<typename T> 672 typename std::enable_if<missingTraits<T>::value, void>::type 673 yamlize(IO &io, T &Val, bool) { 674 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 675 } 676 677 template<typename T> 678 typename std::enable_if<has_SequenceTraits<T>::value,void>::type 679 yamlize(IO &io, T &Seq, bool) { 680 if ( has_FlowTraits< SequenceTraits<T> >::value ) { 681 unsigned incnt = io.beginFlowSequence(); 682 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 683 for(unsigned i=0; i < count; ++i) { 684 void *SaveInfo; 685 if ( io.preflightFlowElement(i, SaveInfo) ) { 686 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true); 687 io.postflightFlowElement(SaveInfo); 688 } 689 } 690 io.endFlowSequence(); 691 } 692 else { 693 unsigned incnt = io.beginSequence(); 694 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 695 for(unsigned i=0; i < count; ++i) { 696 void *SaveInfo; 697 if ( io.preflightElement(i, SaveInfo) ) { 698 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true); 699 io.postflightElement(SaveInfo); 700 } 701 } 702 io.endSequence(); 703 } 704 } 705 706 707 template<> 708 struct ScalarTraits<bool> { 709 static void output(const bool &, void*, llvm::raw_ostream &); 710 static StringRef input(StringRef, void*, bool &); 711 static bool mustQuote(StringRef) { return false; } 712 }; 713 714 template<> 715 struct ScalarTraits<StringRef> { 716 static void output(const StringRef &, void*, llvm::raw_ostream &); 717 static StringRef input(StringRef, void*, StringRef &); 718 static bool mustQuote(StringRef S) { return needsQuotes(S); } 719 }; 720 721 template<> 722 struct ScalarTraits<std::string> { 723 static void output(const std::string &, void*, llvm::raw_ostream &); 724 static StringRef input(StringRef, void*, std::string &); 725 static bool mustQuote(StringRef S) { return needsQuotes(S); } 726 }; 727 728 template<> 729 struct ScalarTraits<uint8_t> { 730 static void output(const uint8_t &, void*, llvm::raw_ostream &); 731 static StringRef input(StringRef, void*, uint8_t &); 732 static bool mustQuote(StringRef) { return false; } 733 }; 734 735 template<> 736 struct ScalarTraits<uint16_t> { 737 static void output(const uint16_t &, void*, llvm::raw_ostream &); 738 static StringRef input(StringRef, void*, uint16_t &); 739 static bool mustQuote(StringRef) { return false; } 740 }; 741 742 template<> 743 struct ScalarTraits<uint32_t> { 744 static void output(const uint32_t &, void*, llvm::raw_ostream &); 745 static StringRef input(StringRef, void*, uint32_t &); 746 static bool mustQuote(StringRef) { return false; } 747 }; 748 749 template<> 750 struct ScalarTraits<uint64_t> { 751 static void output(const uint64_t &, void*, llvm::raw_ostream &); 752 static StringRef input(StringRef, void*, uint64_t &); 753 static bool mustQuote(StringRef) { return false; } 754 }; 755 756 template<> 757 struct ScalarTraits<int8_t> { 758 static void output(const int8_t &, void*, llvm::raw_ostream &); 759 static StringRef input(StringRef, void*, int8_t &); 760 static bool mustQuote(StringRef) { return false; } 761 }; 762 763 template<> 764 struct ScalarTraits<int16_t> { 765 static void output(const int16_t &, void*, llvm::raw_ostream &); 766 static StringRef input(StringRef, void*, int16_t &); 767 static bool mustQuote(StringRef) { return false; } 768 }; 769 770 template<> 771 struct ScalarTraits<int32_t> { 772 static void output(const int32_t &, void*, llvm::raw_ostream &); 773 static StringRef input(StringRef, void*, int32_t &); 774 static bool mustQuote(StringRef) { return false; } 775 }; 776 777 template<> 778 struct ScalarTraits<int64_t> { 779 static void output(const int64_t &, void*, llvm::raw_ostream &); 780 static StringRef input(StringRef, void*, int64_t &); 781 static bool mustQuote(StringRef) { return false; } 782 }; 783 784 template<> 785 struct ScalarTraits<float> { 786 static void output(const float &, void*, llvm::raw_ostream &); 787 static StringRef input(StringRef, void*, float &); 788 static bool mustQuote(StringRef) { return false; } 789 }; 790 791 template<> 792 struct ScalarTraits<double> { 793 static void output(const double &, void*, llvm::raw_ostream &); 794 static StringRef input(StringRef, void*, double &); 795 static bool mustQuote(StringRef) { return false; } 796 }; 797 798 799 800 // Utility for use within MappingTraits<>::mapping() method 801 // to [de]normalize an object for use with YAML conversion. 802 template <typename TNorm, typename TFinal> 803 struct MappingNormalization { 804 MappingNormalization(IO &i_o, TFinal &Obj) 805 : io(i_o), BufPtr(nullptr), Result(Obj) { 806 if ( io.outputting() ) { 807 BufPtr = new (&Buffer) TNorm(io, Obj); 808 } 809 else { 810 BufPtr = new (&Buffer) TNorm(io); 811 } 812 } 813 814 ~MappingNormalization() { 815 if ( ! io.outputting() ) { 816 Result = BufPtr->denormalize(io); 817 } 818 BufPtr->~TNorm(); 819 } 820 821 TNorm* operator->() { return BufPtr; } 822 823 private: 824 typedef llvm::AlignedCharArrayUnion<TNorm> Storage; 825 826 Storage Buffer; 827 IO &io; 828 TNorm *BufPtr; 829 TFinal &Result; 830 }; 831 832 833 834 // Utility for use within MappingTraits<>::mapping() method 835 // to [de]normalize an object for use with YAML conversion. 836 template <typename TNorm, typename TFinal> 837 struct MappingNormalizationHeap { 838 MappingNormalizationHeap(IO &i_o, TFinal &Obj) 839 : io(i_o), BufPtr(NULL), Result(Obj) { 840 if ( io.outputting() ) { 841 BufPtr = new (&Buffer) TNorm(io, Obj); 842 } 843 else { 844 BufPtr = new TNorm(io); 845 } 846 } 847 848 ~MappingNormalizationHeap() { 849 if ( io.outputting() ) { 850 BufPtr->~TNorm(); 851 } 852 else { 853 Result = BufPtr->denormalize(io); 854 } 855 } 856 857 TNorm* operator->() { return BufPtr; } 858 859 private: 860 typedef llvm::AlignedCharArrayUnion<TNorm> Storage; 861 862 Storage Buffer; 863 IO &io; 864 TNorm *BufPtr; 865 TFinal &Result; 866 }; 867 868 869 870 /// 871 /// The Input class is used to parse a yaml document into in-memory structs 872 /// and vectors. 873 /// 874 /// It works by using YAMLParser to do a syntax parse of the entire yaml 875 /// document, then the Input class builds a graph of HNodes which wraps 876 /// each yaml Node. The extra layer is buffering. The low level yaml 877 /// parser only lets you look at each node once. The buffering layer lets 878 /// you search and interate multiple times. This is necessary because 879 /// the mapRequired() method calls may not be in the same order 880 /// as the keys in the document. 881 /// 882 class Input : public IO { 883 public: 884 // Construct a yaml Input object from a StringRef and optional 885 // user-data. The DiagHandler can be specified to provide 886 // alternative error reporting. 887 Input(StringRef InputContent, 888 void *Ctxt = nullptr, 889 SourceMgr::DiagHandlerTy DiagHandler = nullptr, 890 void *DiagHandlerCtxt = nullptr); 891 ~Input() override; 892 893 // Check if there was an syntax or semantic error during parsing. 894 std::error_code error(); 895 896 private: 897 bool outputting() override; 898 bool mapTag(StringRef, bool) override; 899 void beginMapping() override; 900 void endMapping() override; 901 bool preflightKey(const char *, bool, bool, bool &, void *&) override; 902 void postflightKey(void *) override; 903 unsigned beginSequence() override; 904 void endSequence() override; 905 bool preflightElement(unsigned index, void *&) override; 906 void postflightElement(void *) override; 907 unsigned beginFlowSequence() override; 908 bool preflightFlowElement(unsigned , void *&) override; 909 void postflightFlowElement(void *) override; 910 void endFlowSequence() override; 911 void beginEnumScalar() override; 912 bool matchEnumScalar(const char*, bool) override; 913 bool matchEnumFallback() override; 914 void endEnumScalar() override; 915 bool beginBitSetScalar(bool &) override; 916 bool bitSetMatch(const char *, bool ) override; 917 void endBitSetScalar() override; 918 void scalarString(StringRef &, bool) override; 919 void setError(const Twine &message) override; 920 bool canElideEmptySequence() override; 921 922 class HNode { 923 virtual void anchor(); 924 public: 925 HNode(Node *n) : _node(n) { } 926 virtual ~HNode() { } 927 static inline bool classof(const HNode *) { return true; } 928 929 Node *_node; 930 }; 931 932 class EmptyHNode : public HNode { 933 void anchor() override; 934 public: 935 EmptyHNode(Node *n) : HNode(n) { } 936 static inline bool classof(const HNode *n) { 937 return NullNode::classof(n->_node); 938 } 939 static inline bool classof(const EmptyHNode *) { return true; } 940 }; 941 942 class ScalarHNode : public HNode { 943 void anchor() override; 944 public: 945 ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { } 946 947 StringRef value() const { return _value; } 948 949 static inline bool classof(const HNode *n) { 950 return ScalarNode::classof(n->_node); 951 } 952 static inline bool classof(const ScalarHNode *) { return true; } 953 protected: 954 StringRef _value; 955 }; 956 957 class MapHNode : public HNode { 958 void anchor() override; 959 960 public: 961 MapHNode(Node *n) : HNode(n) { } 962 963 static inline bool classof(const HNode *n) { 964 return MappingNode::classof(n->_node); 965 } 966 static inline bool classof(const MapHNode *) { return true; } 967 968 typedef llvm::StringMap<std::unique_ptr<HNode>> NameToNode; 969 970 bool isValidKey(StringRef key); 971 972 NameToNode Mapping; 973 llvm::SmallVector<const char*, 6> ValidKeys; 974 }; 975 976 class SequenceHNode : public HNode { 977 void anchor() override; 978 979 public: 980 SequenceHNode(Node *n) : HNode(n) { } 981 982 static inline bool classof(const HNode *n) { 983 return SequenceNode::classof(n->_node); 984 } 985 static inline bool classof(const SequenceHNode *) { return true; } 986 987 std::vector<std::unique_ptr<HNode>> Entries; 988 }; 989 990 std::unique_ptr<Input::HNode> createHNodes(Node *node); 991 void setError(HNode *hnode, const Twine &message); 992 void setError(Node *node, const Twine &message); 993 994 995 public: 996 // These are only used by operator>>. They could be private 997 // if those templated things could be made friends. 998 bool setCurrentDocument(); 999 bool nextDocument(); 1000 1001 private: 1002 llvm::SourceMgr SrcMgr; // must be before Strm 1003 std::unique_ptr<llvm::yaml::Stream> Strm; 1004 std::unique_ptr<HNode> TopNode; 1005 std::error_code EC; 1006 llvm::BumpPtrAllocator StringAllocator; 1007 llvm::yaml::document_iterator DocIterator; 1008 std::vector<bool> BitValuesUsed; 1009 HNode *CurrentNode; 1010 bool ScalarMatchFound; 1011 }; 1012 1013 1014 1015 1016 /// 1017 /// The Output class is used to generate a yaml document from in-memory structs 1018 /// and vectors. 1019 /// 1020 class Output : public IO { 1021 public: 1022 Output(llvm::raw_ostream &, void *Ctxt=nullptr); 1023 ~Output() override; 1024 1025 bool outputting() override; 1026 bool mapTag(StringRef, bool) override; 1027 void beginMapping() override; 1028 void endMapping() override; 1029 bool preflightKey(const char *key, bool, bool, bool &, void *&) override; 1030 void postflightKey(void *) override; 1031 unsigned beginSequence() override; 1032 void endSequence() override; 1033 bool preflightElement(unsigned, void *&) override; 1034 void postflightElement(void *) override; 1035 unsigned beginFlowSequence() override; 1036 bool preflightFlowElement(unsigned, void *&) override; 1037 void postflightFlowElement(void *) override; 1038 void endFlowSequence() override; 1039 void beginEnumScalar() override; 1040 bool matchEnumScalar(const char*, bool) override; 1041 bool matchEnumFallback() override; 1042 void endEnumScalar() override; 1043 bool beginBitSetScalar(bool &) override; 1044 bool bitSetMatch(const char *, bool ) override; 1045 void endBitSetScalar() override; 1046 void scalarString(StringRef &, bool) override; 1047 void setError(const Twine &message) override; 1048 bool canElideEmptySequence() override; 1049 public: 1050 // These are only used by operator<<. They could be private 1051 // if that templated operator could be made a friend. 1052 void beginDocuments(); 1053 bool preflightDocument(unsigned); 1054 void postflightDocument(); 1055 void endDocuments(); 1056 1057 private: 1058 void output(StringRef s); 1059 void outputUpToEndOfLine(StringRef s); 1060 void newLineCheck(); 1061 void outputNewLine(); 1062 void paddedKey(StringRef key); 1063 1064 enum InState { inSeq, inFlowSeq, inMapFirstKey, inMapOtherKey }; 1065 1066 llvm::raw_ostream &Out; 1067 SmallVector<InState, 8> StateStack; 1068 int Column; 1069 int ColumnAtFlowStart; 1070 bool NeedBitValueComma; 1071 bool NeedFlowSequenceComma; 1072 bool EnumerationMatchFound; 1073 bool NeedsNewLine; 1074 }; 1075 1076 1077 1078 1079 /// YAML I/O does conversion based on types. But often native data types 1080 /// are just a typedef of built in intergral types (e.g. int). But the C++ 1081 /// type matching system sees through the typedef and all the typedefed types 1082 /// look like a built in type. This will cause the generic YAML I/O conversion 1083 /// to be used. To provide better control over the YAML conversion, you can 1084 /// use this macro instead of typedef. It will create a class with one field 1085 /// and automatic conversion operators to and from the base type. 1086 /// Based on BOOST_STRONG_TYPEDEF 1087 #define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ 1088 struct _type { \ 1089 _type() { } \ 1090 _type(const _base v) : value(v) { } \ 1091 _type(const _type &v) : value(v.value) {} \ 1092 _type &operator=(const _type &rhs) { value = rhs.value; return *this; }\ 1093 _type &operator=(const _base &rhs) { value = rhs; return *this; } \ 1094 operator const _base & () const { return value; } \ 1095 bool operator==(const _type &rhs) const { return value == rhs.value; } \ 1096 bool operator==(const _base &rhs) const { return value == rhs; } \ 1097 bool operator<(const _type &rhs) const { return value < rhs.value; } \ 1098 _base value; \ 1099 }; 1100 1101 1102 1103 /// 1104 /// Use these types instead of uintXX_t in any mapping to have 1105 /// its yaml output formatted as hexadecimal. 1106 /// 1107 LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) 1108 LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) 1109 LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) 1110 LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) 1111 1112 1113 template<> 1114 struct ScalarTraits<Hex8> { 1115 static void output(const Hex8 &, void*, llvm::raw_ostream &); 1116 static StringRef input(StringRef, void*, Hex8 &); 1117 static bool mustQuote(StringRef) { return false; } 1118 }; 1119 1120 template<> 1121 struct ScalarTraits<Hex16> { 1122 static void output(const Hex16 &, void*, llvm::raw_ostream &); 1123 static StringRef input(StringRef, void*, Hex16 &); 1124 static bool mustQuote(StringRef) { return false; } 1125 }; 1126 1127 template<> 1128 struct ScalarTraits<Hex32> { 1129 static void output(const Hex32 &, void*, llvm::raw_ostream &); 1130 static StringRef input(StringRef, void*, Hex32 &); 1131 static bool mustQuote(StringRef) { return false; } 1132 }; 1133 1134 template<> 1135 struct ScalarTraits<Hex64> { 1136 static void output(const Hex64 &, void*, llvm::raw_ostream &); 1137 static StringRef input(StringRef, void*, Hex64 &); 1138 static bool mustQuote(StringRef) { return false; } 1139 }; 1140 1141 1142 // Define non-member operator>> so that Input can stream in a document list. 1143 template <typename T> 1144 inline 1145 typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type 1146 operator>>(Input &yin, T &docList) { 1147 int i = 0; 1148 while ( yin.setCurrentDocument() ) { 1149 yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true); 1150 if ( yin.error() ) 1151 return yin; 1152 yin.nextDocument(); 1153 ++i; 1154 } 1155 return yin; 1156 } 1157 1158 // Define non-member operator>> so that Input can stream in a map as a document. 1159 template <typename T> 1160 inline 1161 typename std::enable_if<has_MappingTraits<T>::value, Input &>::type 1162 operator>>(Input &yin, T &docMap) { 1163 yin.setCurrentDocument(); 1164 yamlize(yin, docMap, true); 1165 return yin; 1166 } 1167 1168 // Define non-member operator>> so that Input can stream in a sequence as 1169 // a document. 1170 template <typename T> 1171 inline 1172 typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type 1173 operator>>(Input &yin, T &docSeq) { 1174 if (yin.setCurrentDocument()) 1175 yamlize(yin, docSeq, true); 1176 return yin; 1177 } 1178 1179 // Provide better error message about types missing a trait specialization 1180 template <typename T> 1181 inline 1182 typename std::enable_if<missingTraits<T>::value, Input &>::type 1183 operator>>(Input &yin, T &docSeq) { 1184 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1185 return yin; 1186 } 1187 1188 1189 // Define non-member operator<< so that Output can stream out document list. 1190 template <typename T> 1191 inline 1192 typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type 1193 operator<<(Output &yout, T &docList) { 1194 yout.beginDocuments(); 1195 const size_t count = DocumentListTraits<T>::size(yout, docList); 1196 for(size_t i=0; i < count; ++i) { 1197 if ( yout.preflightDocument(i) ) { 1198 yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true); 1199 yout.postflightDocument(); 1200 } 1201 } 1202 yout.endDocuments(); 1203 return yout; 1204 } 1205 1206 // Define non-member operator<< so that Output can stream out a map. 1207 template <typename T> 1208 inline 1209 typename std::enable_if<has_MappingTraits<T>::value, Output &>::type 1210 operator<<(Output &yout, T &map) { 1211 yout.beginDocuments(); 1212 if ( yout.preflightDocument(0) ) { 1213 yamlize(yout, map, true); 1214 yout.postflightDocument(); 1215 } 1216 yout.endDocuments(); 1217 return yout; 1218 } 1219 1220 // Define non-member operator<< so that Output can stream out a sequence. 1221 template <typename T> 1222 inline 1223 typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type 1224 operator<<(Output &yout, T &seq) { 1225 yout.beginDocuments(); 1226 if ( yout.preflightDocument(0) ) { 1227 yamlize(yout, seq, true); 1228 yout.postflightDocument(); 1229 } 1230 yout.endDocuments(); 1231 return yout; 1232 } 1233 1234 // Provide better error message about types missing a trait specialization 1235 template <typename T> 1236 inline 1237 typename std::enable_if<missingTraits<T>::value, Output &>::type 1238 operator<<(Output &yout, T &seq) { 1239 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1240 return yout; 1241 } 1242 1243 1244 } // namespace yaml 1245 } // namespace llvm 1246 1247 1248 /// Utility for declaring that a std::vector of a particular type 1249 /// should be considered a YAML sequence. 1250 #define LLVM_YAML_IS_SEQUENCE_VECTOR(_type) \ 1251 namespace llvm { \ 1252 namespace yaml { \ 1253 template<> \ 1254 struct SequenceTraits< std::vector<_type> > { \ 1255 static size_t size(IO &io, std::vector<_type> &seq) { \ 1256 return seq.size(); \ 1257 } \ 1258 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1259 if ( index >= seq.size() ) \ 1260 seq.resize(index+1); \ 1261 return seq[index]; \ 1262 } \ 1263 }; \ 1264 } \ 1265 } 1266 1267 /// Utility for declaring that a std::vector of a particular type 1268 /// should be considered a YAML flow sequence. 1269 #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type) \ 1270 namespace llvm { \ 1271 namespace yaml { \ 1272 template<> \ 1273 struct SequenceTraits< std::vector<_type> > { \ 1274 static size_t size(IO &io, std::vector<_type> &seq) { \ 1275 return seq.size(); \ 1276 } \ 1277 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1278 (void)flow; /* Remove this workaround after PR17897 is fixed */ \ 1279 if ( index >= seq.size() ) \ 1280 seq.resize(index+1); \ 1281 return seq[index]; \ 1282 } \ 1283 static const bool flow = true; \ 1284 }; \ 1285 } \ 1286 } 1287 1288 /// Utility for declaring that a std::vector of a particular type 1289 /// should be considered a YAML document list. 1290 #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ 1291 namespace llvm { \ 1292 namespace yaml { \ 1293 template<> \ 1294 struct DocumentListTraits< std::vector<_type> > { \ 1295 static size_t size(IO &io, std::vector<_type> &seq) { \ 1296 return seq.size(); \ 1297 } \ 1298 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1299 if ( index >= seq.size() ) \ 1300 seq.resize(index+1); \ 1301 return seq[index]; \ 1302 } \ 1303 }; \ 1304 } \ 1305 } 1306 1307 1308 1309 #endif // LLVM_SUPPORT_YAMLTRAITS_H 1310