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 void endEnumScalar() = 0; 451 452 virtual bool beginBitSetScalar(bool &) = 0; 453 virtual bool bitSetMatch(const char*, bool) = 0; 454 virtual void endBitSetScalar() = 0; 455 456 virtual void scalarString(StringRef &, bool) = 0; 457 458 virtual void setError(const Twine &) = 0; 459 460 template <typename T> 461 void enumCase(T &Val, const char* Str, const T ConstVal) { 462 if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) { 463 Val = ConstVal; 464 } 465 } 466 467 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 468 template <typename T> 469 void enumCase(T &Val, const char* Str, const uint32_t ConstVal) { 470 if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) { 471 Val = ConstVal; 472 } 473 } 474 475 template <typename T> 476 void bitSetCase(T &Val, const char* Str, const T ConstVal) { 477 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 478 Val = Val | ConstVal; 479 } 480 } 481 482 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF 483 template <typename T> 484 void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) { 485 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) { 486 Val = Val | ConstVal; 487 } 488 } 489 490 template <typename T> 491 void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) { 492 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 493 Val = Val | ConstVal; 494 } 495 496 template <typename T> 497 void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal, 498 uint32_t Mask) { 499 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal)) 500 Val = Val | ConstVal; 501 } 502 503 void *getContext(); 504 void setContext(void *); 505 506 template <typename T> 507 void mapRequired(const char* Key, T& Val) { 508 this->processKey(Key, Val, true); 509 } 510 511 template <typename T> 512 typename std::enable_if<has_SequenceTraits<T>::value,void>::type 513 mapOptional(const char* Key, T& Val) { 514 // omit key/value instead of outputting empty sequence 515 if ( this->canElideEmptySequence() && !(Val.begin() != Val.end()) ) 516 return; 517 this->processKey(Key, Val, false); 518 } 519 520 template <typename T> 521 void mapOptional(const char* Key, Optional<T> &Val) { 522 processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false); 523 } 524 525 template <typename T> 526 typename std::enable_if<!has_SequenceTraits<T>::value,void>::type 527 mapOptional(const char* Key, T& Val) { 528 this->processKey(Key, Val, false); 529 } 530 531 template <typename T> 532 void mapOptional(const char* Key, T& Val, const T& Default) { 533 this->processKeyWithDefault(Key, Val, Default, false); 534 } 535 536 private: 537 template <typename T> 538 void processKeyWithDefault(const char *Key, Optional<T> &Val, 539 const Optional<T> &DefaultValue, bool Required) { 540 assert(DefaultValue.hasValue() == false && 541 "Optional<T> shouldn't have a value!"); 542 void *SaveInfo; 543 bool UseDefault; 544 const bool sameAsDefault = outputting() && !Val.hasValue(); 545 if (!outputting() && !Val.hasValue()) 546 Val = T(); 547 if (this->preflightKey(Key, Required, sameAsDefault, UseDefault, 548 SaveInfo)) { 549 yamlize(*this, Val.getValue(), Required); 550 this->postflightKey(SaveInfo); 551 } else { 552 if (UseDefault) 553 Val = DefaultValue; 554 } 555 } 556 557 template <typename T> 558 void processKeyWithDefault(const char *Key, T &Val, const T& DefaultValue, 559 bool Required) { 560 void *SaveInfo; 561 bool UseDefault; 562 const bool sameAsDefault = outputting() && Val == DefaultValue; 563 if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault, 564 SaveInfo) ) { 565 yamlize(*this, Val, Required); 566 this->postflightKey(SaveInfo); 567 } 568 else { 569 if ( UseDefault ) 570 Val = DefaultValue; 571 } 572 } 573 574 template <typename T> 575 void processKey(const char *Key, T &Val, bool Required) { 576 void *SaveInfo; 577 bool UseDefault; 578 if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) { 579 yamlize(*this, Val, Required); 580 this->postflightKey(SaveInfo); 581 } 582 } 583 584 private: 585 void *Ctxt; 586 }; 587 588 589 590 template<typename T> 591 typename std::enable_if<has_ScalarEnumerationTraits<T>::value,void>::type 592 yamlize(IO &io, T &Val, bool) { 593 io.beginEnumScalar(); 594 ScalarEnumerationTraits<T>::enumeration(io, Val); 595 io.endEnumScalar(); 596 } 597 598 template<typename T> 599 typename std::enable_if<has_ScalarBitSetTraits<T>::value,void>::type 600 yamlize(IO &io, T &Val, bool) { 601 bool DoClear; 602 if ( io.beginBitSetScalar(DoClear) ) { 603 if ( DoClear ) 604 Val = static_cast<T>(0); 605 ScalarBitSetTraits<T>::bitset(io, Val); 606 io.endBitSetScalar(); 607 } 608 } 609 610 611 template<typename T> 612 typename std::enable_if<has_ScalarTraits<T>::value,void>::type 613 yamlize(IO &io, T &Val, bool) { 614 if ( io.outputting() ) { 615 std::string Storage; 616 llvm::raw_string_ostream Buffer(Storage); 617 ScalarTraits<T>::output(Val, io.getContext(), Buffer); 618 StringRef Str = Buffer.str(); 619 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); 620 } 621 else { 622 StringRef Str; 623 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str)); 624 StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val); 625 if ( !Result.empty() ) { 626 io.setError(llvm::Twine(Result)); 627 } 628 } 629 } 630 631 632 template<typename T> 633 typename std::enable_if<validatedMappingTraits<T>::value, void>::type 634 yamlize(IO &io, T &Val, bool) { 635 io.beginMapping(); 636 if (io.outputting()) { 637 StringRef Err = MappingTraits<T>::validate(io, Val); 638 if (!Err.empty()) { 639 llvm::errs() << Err << "\n"; 640 assert(Err.empty() && "invalid struct trying to be written as yaml"); 641 } 642 } 643 MappingTraits<T>::mapping(io, Val); 644 if (!io.outputting()) { 645 StringRef Err = MappingTraits<T>::validate(io, Val); 646 if (!Err.empty()) 647 io.setError(Err); 648 } 649 io.endMapping(); 650 } 651 652 template<typename T> 653 typename std::enable_if<unvalidatedMappingTraits<T>::value, void>::type 654 yamlize(IO &io, T &Val, bool) { 655 io.beginMapping(); 656 MappingTraits<T>::mapping(io, Val); 657 io.endMapping(); 658 } 659 660 template<typename T> 661 typename std::enable_if<missingTraits<T>::value, void>::type 662 yamlize(IO &io, T &Val, bool) { 663 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 664 } 665 666 template<typename T> 667 typename std::enable_if<has_SequenceTraits<T>::value,void>::type 668 yamlize(IO &io, T &Seq, bool) { 669 if ( has_FlowTraits< SequenceTraits<T> >::value ) { 670 unsigned incnt = io.beginFlowSequence(); 671 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 672 for(unsigned i=0; i < count; ++i) { 673 void *SaveInfo; 674 if ( io.preflightFlowElement(i, SaveInfo) ) { 675 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true); 676 io.postflightFlowElement(SaveInfo); 677 } 678 } 679 io.endFlowSequence(); 680 } 681 else { 682 unsigned incnt = io.beginSequence(); 683 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt; 684 for(unsigned i=0; i < count; ++i) { 685 void *SaveInfo; 686 if ( io.preflightElement(i, SaveInfo) ) { 687 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true); 688 io.postflightElement(SaveInfo); 689 } 690 } 691 io.endSequence(); 692 } 693 } 694 695 696 template<> 697 struct ScalarTraits<bool> { 698 static void output(const bool &, void*, llvm::raw_ostream &); 699 static StringRef input(StringRef, void*, bool &); 700 static bool mustQuote(StringRef) { return false; } 701 }; 702 703 template<> 704 struct ScalarTraits<StringRef> { 705 static void output(const StringRef &, void*, llvm::raw_ostream &); 706 static StringRef input(StringRef, void*, StringRef &); 707 static bool mustQuote(StringRef S) { return needsQuotes(S); } 708 }; 709 710 template<> 711 struct ScalarTraits<std::string> { 712 static void output(const std::string &, void*, llvm::raw_ostream &); 713 static StringRef input(StringRef, void*, std::string &); 714 static bool mustQuote(StringRef S) { return needsQuotes(S); } 715 }; 716 717 template<> 718 struct ScalarTraits<uint8_t> { 719 static void output(const uint8_t &, void*, llvm::raw_ostream &); 720 static StringRef input(StringRef, void*, uint8_t &); 721 static bool mustQuote(StringRef) { return false; } 722 }; 723 724 template<> 725 struct ScalarTraits<uint16_t> { 726 static void output(const uint16_t &, void*, llvm::raw_ostream &); 727 static StringRef input(StringRef, void*, uint16_t &); 728 static bool mustQuote(StringRef) { return false; } 729 }; 730 731 template<> 732 struct ScalarTraits<uint32_t> { 733 static void output(const uint32_t &, void*, llvm::raw_ostream &); 734 static StringRef input(StringRef, void*, uint32_t &); 735 static bool mustQuote(StringRef) { return false; } 736 }; 737 738 template<> 739 struct ScalarTraits<uint64_t> { 740 static void output(const uint64_t &, void*, llvm::raw_ostream &); 741 static StringRef input(StringRef, void*, uint64_t &); 742 static bool mustQuote(StringRef) { return false; } 743 }; 744 745 template<> 746 struct ScalarTraits<int8_t> { 747 static void output(const int8_t &, void*, llvm::raw_ostream &); 748 static StringRef input(StringRef, void*, int8_t &); 749 static bool mustQuote(StringRef) { return false; } 750 }; 751 752 template<> 753 struct ScalarTraits<int16_t> { 754 static void output(const int16_t &, void*, llvm::raw_ostream &); 755 static StringRef input(StringRef, void*, int16_t &); 756 static bool mustQuote(StringRef) { return false; } 757 }; 758 759 template<> 760 struct ScalarTraits<int32_t> { 761 static void output(const int32_t &, void*, llvm::raw_ostream &); 762 static StringRef input(StringRef, void*, int32_t &); 763 static bool mustQuote(StringRef) { return false; } 764 }; 765 766 template<> 767 struct ScalarTraits<int64_t> { 768 static void output(const int64_t &, void*, llvm::raw_ostream &); 769 static StringRef input(StringRef, void*, int64_t &); 770 static bool mustQuote(StringRef) { return false; } 771 }; 772 773 template<> 774 struct ScalarTraits<float> { 775 static void output(const float &, void*, llvm::raw_ostream &); 776 static StringRef input(StringRef, void*, float &); 777 static bool mustQuote(StringRef) { return false; } 778 }; 779 780 template<> 781 struct ScalarTraits<double> { 782 static void output(const double &, void*, llvm::raw_ostream &); 783 static StringRef input(StringRef, void*, double &); 784 static bool mustQuote(StringRef) { return false; } 785 }; 786 787 788 789 // Utility for use within MappingTraits<>::mapping() method 790 // to [de]normalize an object for use with YAML conversion. 791 template <typename TNorm, typename TFinal> 792 struct MappingNormalization { 793 MappingNormalization(IO &i_o, TFinal &Obj) 794 : io(i_o), BufPtr(nullptr), Result(Obj) { 795 if ( io.outputting() ) { 796 BufPtr = new (&Buffer) TNorm(io, Obj); 797 } 798 else { 799 BufPtr = new (&Buffer) TNorm(io); 800 } 801 } 802 803 ~MappingNormalization() { 804 if ( ! io.outputting() ) { 805 Result = BufPtr->denormalize(io); 806 } 807 BufPtr->~TNorm(); 808 } 809 810 TNorm* operator->() { return BufPtr; } 811 812 private: 813 typedef llvm::AlignedCharArrayUnion<TNorm> Storage; 814 815 Storage Buffer; 816 IO &io; 817 TNorm *BufPtr; 818 TFinal &Result; 819 }; 820 821 822 823 // Utility for use within MappingTraits<>::mapping() method 824 // to [de]normalize an object for use with YAML conversion. 825 template <typename TNorm, typename TFinal> 826 struct MappingNormalizationHeap { 827 MappingNormalizationHeap(IO &i_o, TFinal &Obj) 828 : io(i_o), BufPtr(NULL), Result(Obj) { 829 if ( io.outputting() ) { 830 BufPtr = new (&Buffer) TNorm(io, Obj); 831 } 832 else { 833 BufPtr = new TNorm(io); 834 } 835 } 836 837 ~MappingNormalizationHeap() { 838 if ( io.outputting() ) { 839 BufPtr->~TNorm(); 840 } 841 else { 842 Result = BufPtr->denormalize(io); 843 } 844 } 845 846 TNorm* operator->() { return BufPtr; } 847 848 private: 849 typedef llvm::AlignedCharArrayUnion<TNorm> Storage; 850 851 Storage Buffer; 852 IO &io; 853 TNorm *BufPtr; 854 TFinal &Result; 855 }; 856 857 858 859 /// 860 /// The Input class is used to parse a yaml document into in-memory structs 861 /// and vectors. 862 /// 863 /// It works by using YAMLParser to do a syntax parse of the entire yaml 864 /// document, then the Input class builds a graph of HNodes which wraps 865 /// each yaml Node. The extra layer is buffering. The low level yaml 866 /// parser only lets you look at each node once. The buffering layer lets 867 /// you search and interate multiple times. This is necessary because 868 /// the mapRequired() method calls may not be in the same order 869 /// as the keys in the document. 870 /// 871 class Input : public IO { 872 public: 873 // Construct a yaml Input object from a StringRef and optional 874 // user-data. The DiagHandler can be specified to provide 875 // alternative error reporting. 876 Input(StringRef InputContent, 877 void *Ctxt = nullptr, 878 SourceMgr::DiagHandlerTy DiagHandler = nullptr, 879 void *DiagHandlerCtxt = nullptr); 880 ~Input(); 881 882 // Check if there was an syntax or semantic error during parsing. 883 std::error_code error(); 884 885 private: 886 bool outputting() override; 887 bool mapTag(StringRef, bool) override; 888 void beginMapping() override; 889 void endMapping() override; 890 bool preflightKey(const char *, bool, bool, bool &, void *&) override; 891 void postflightKey(void *) override; 892 unsigned beginSequence() override; 893 void endSequence() override; 894 bool preflightElement(unsigned index, void *&) override; 895 void postflightElement(void *) override; 896 unsigned beginFlowSequence() override; 897 bool preflightFlowElement(unsigned , void *&) override; 898 void postflightFlowElement(void *) override; 899 void endFlowSequence() override; 900 void beginEnumScalar() override; 901 bool matchEnumScalar(const char*, bool) override; 902 void endEnumScalar() override; 903 bool beginBitSetScalar(bool &) override; 904 bool bitSetMatch(const char *, bool ) override; 905 void endBitSetScalar() override; 906 void scalarString(StringRef &, bool) override; 907 void setError(const Twine &message) override; 908 bool canElideEmptySequence() override; 909 910 class HNode { 911 virtual void anchor(); 912 public: 913 HNode(Node *n) : _node(n) { } 914 virtual ~HNode() { } 915 static inline bool classof(const HNode *) { return true; } 916 917 Node *_node; 918 }; 919 920 class EmptyHNode : public HNode { 921 void anchor() override; 922 public: 923 EmptyHNode(Node *n) : HNode(n) { } 924 static inline bool classof(const HNode *n) { 925 return NullNode::classof(n->_node); 926 } 927 static inline bool classof(const EmptyHNode *) { return true; } 928 }; 929 930 class ScalarHNode : public HNode { 931 void anchor() override; 932 public: 933 ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { } 934 935 StringRef value() const { return _value; } 936 937 static inline bool classof(const HNode *n) { 938 return ScalarNode::classof(n->_node); 939 } 940 static inline bool classof(const ScalarHNode *) { return true; } 941 protected: 942 StringRef _value; 943 }; 944 945 class MapHNode : public HNode { 946 public: 947 MapHNode(Node *n) : HNode(n) { } 948 virtual ~MapHNode(); 949 950 static inline bool classof(const HNode *n) { 951 return MappingNode::classof(n->_node); 952 } 953 static inline bool classof(const MapHNode *) { return true; } 954 955 typedef llvm::StringMap<HNode*> NameToNode; 956 957 bool isValidKey(StringRef key); 958 959 NameToNode Mapping; 960 llvm::SmallVector<const char*, 6> ValidKeys; 961 }; 962 963 class SequenceHNode : public HNode { 964 public: 965 SequenceHNode(Node *n) : HNode(n) { } 966 virtual ~SequenceHNode(); 967 968 static inline bool classof(const HNode *n) { 969 return SequenceNode::classof(n->_node); 970 } 971 static inline bool classof(const SequenceHNode *) { return true; } 972 973 std::vector<HNode*> Entries; 974 }; 975 976 Input::HNode *createHNodes(Node *node); 977 void setError(HNode *hnode, const Twine &message); 978 void setError(Node *node, const Twine &message); 979 980 981 public: 982 // These are only used by operator>>. They could be private 983 // if those templated things could be made friends. 984 bool setCurrentDocument(); 985 bool nextDocument(); 986 987 private: 988 llvm::SourceMgr SrcMgr; // must be before Strm 989 std::unique_ptr<llvm::yaml::Stream> Strm; 990 std::unique_ptr<HNode> TopNode; 991 std::error_code EC; 992 llvm::BumpPtrAllocator StringAllocator; 993 llvm::yaml::document_iterator DocIterator; 994 std::vector<bool> BitValuesUsed; 995 HNode *CurrentNode; 996 bool ScalarMatchFound; 997 }; 998 999 1000 1001 1002 /// 1003 /// The Output class is used to generate a yaml document from in-memory structs 1004 /// and vectors. 1005 /// 1006 class Output : public IO { 1007 public: 1008 Output(llvm::raw_ostream &, void *Ctxt=nullptr); 1009 virtual ~Output(); 1010 1011 bool outputting() override; 1012 bool mapTag(StringRef, bool) override; 1013 void beginMapping() override; 1014 void endMapping() override; 1015 bool preflightKey(const char *key, bool, bool, bool &, void *&) override; 1016 void postflightKey(void *) override; 1017 unsigned beginSequence() override; 1018 void endSequence() override; 1019 bool preflightElement(unsigned, void *&) override; 1020 void postflightElement(void *) override; 1021 unsigned beginFlowSequence() override; 1022 bool preflightFlowElement(unsigned, void *&) override; 1023 void postflightFlowElement(void *) override; 1024 void endFlowSequence() override; 1025 void beginEnumScalar() override; 1026 bool matchEnumScalar(const char*, bool) override; 1027 void endEnumScalar() override; 1028 bool beginBitSetScalar(bool &) override; 1029 bool bitSetMatch(const char *, bool ) override; 1030 void endBitSetScalar() override; 1031 void scalarString(StringRef &, bool) override; 1032 void setError(const Twine &message) override; 1033 bool canElideEmptySequence() override; 1034 public: 1035 // These are only used by operator<<. They could be private 1036 // if that templated operator could be made a friend. 1037 void beginDocuments(); 1038 bool preflightDocument(unsigned); 1039 void postflightDocument(); 1040 void endDocuments(); 1041 1042 private: 1043 void output(StringRef s); 1044 void outputUpToEndOfLine(StringRef s); 1045 void newLineCheck(); 1046 void outputNewLine(); 1047 void paddedKey(StringRef key); 1048 1049 enum InState { inSeq, inFlowSeq, inMapFirstKey, inMapOtherKey }; 1050 1051 llvm::raw_ostream &Out; 1052 SmallVector<InState, 8> StateStack; 1053 int Column; 1054 int ColumnAtFlowStart; 1055 bool NeedBitValueComma; 1056 bool NeedFlowSequenceComma; 1057 bool EnumerationMatchFound; 1058 bool NeedsNewLine; 1059 }; 1060 1061 1062 1063 1064 /// YAML I/O does conversion based on types. But often native data types 1065 /// are just a typedef of built in intergral types (e.g. int). But the C++ 1066 /// type matching system sees through the typedef and all the typedefed types 1067 /// look like a built in type. This will cause the generic YAML I/O conversion 1068 /// to be used. To provide better control over the YAML conversion, you can 1069 /// use this macro instead of typedef. It will create a class with one field 1070 /// and automatic conversion operators to and from the base type. 1071 /// Based on BOOST_STRONG_TYPEDEF 1072 #define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ 1073 struct _type { \ 1074 _type() { } \ 1075 _type(const _base v) : value(v) { } \ 1076 _type(const _type &v) : value(v.value) {} \ 1077 _type &operator=(const _type &rhs) { value = rhs.value; return *this; }\ 1078 _type &operator=(const _base &rhs) { value = rhs; return *this; } \ 1079 operator const _base & () const { return value; } \ 1080 bool operator==(const _type &rhs) const { return value == rhs.value; } \ 1081 bool operator==(const _base &rhs) const { return value == rhs; } \ 1082 bool operator<(const _type &rhs) const { return value < rhs.value; } \ 1083 _base value; \ 1084 }; 1085 1086 1087 1088 /// 1089 /// Use these types instead of uintXX_t in any mapping to have 1090 /// its yaml output formatted as hexadecimal. 1091 /// 1092 LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) 1093 LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) 1094 LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) 1095 LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) 1096 1097 1098 template<> 1099 struct ScalarTraits<Hex8> { 1100 static void output(const Hex8 &, void*, llvm::raw_ostream &); 1101 static StringRef input(StringRef, void*, Hex8 &); 1102 static bool mustQuote(StringRef) { return false; } 1103 }; 1104 1105 template<> 1106 struct ScalarTraits<Hex16> { 1107 static void output(const Hex16 &, void*, llvm::raw_ostream &); 1108 static StringRef input(StringRef, void*, Hex16 &); 1109 static bool mustQuote(StringRef) { return false; } 1110 }; 1111 1112 template<> 1113 struct ScalarTraits<Hex32> { 1114 static void output(const Hex32 &, void*, llvm::raw_ostream &); 1115 static StringRef input(StringRef, void*, Hex32 &); 1116 static bool mustQuote(StringRef) { return false; } 1117 }; 1118 1119 template<> 1120 struct ScalarTraits<Hex64> { 1121 static void output(const Hex64 &, void*, llvm::raw_ostream &); 1122 static StringRef input(StringRef, void*, Hex64 &); 1123 static bool mustQuote(StringRef) { return false; } 1124 }; 1125 1126 1127 // Define non-member operator>> so that Input can stream in a document list. 1128 template <typename T> 1129 inline 1130 typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type 1131 operator>>(Input &yin, T &docList) { 1132 int i = 0; 1133 while ( yin.setCurrentDocument() ) { 1134 yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true); 1135 if ( yin.error() ) 1136 return yin; 1137 yin.nextDocument(); 1138 ++i; 1139 } 1140 return yin; 1141 } 1142 1143 // Define non-member operator>> so that Input can stream in a map as a document. 1144 template <typename T> 1145 inline 1146 typename std::enable_if<has_MappingTraits<T>::value, Input &>::type 1147 operator>>(Input &yin, T &docMap) { 1148 yin.setCurrentDocument(); 1149 yamlize(yin, docMap, true); 1150 return yin; 1151 } 1152 1153 // Define non-member operator>> so that Input can stream in a sequence as 1154 // a document. 1155 template <typename T> 1156 inline 1157 typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type 1158 operator>>(Input &yin, T &docSeq) { 1159 if (yin.setCurrentDocument()) 1160 yamlize(yin, docSeq, true); 1161 return yin; 1162 } 1163 1164 // Provide better error message about types missing a trait specialization 1165 template <typename T> 1166 inline 1167 typename std::enable_if<missingTraits<T>::value, Input &>::type 1168 operator>>(Input &yin, T &docSeq) { 1169 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1170 return yin; 1171 } 1172 1173 1174 // Define non-member operator<< so that Output can stream out document list. 1175 template <typename T> 1176 inline 1177 typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type 1178 operator<<(Output &yout, T &docList) { 1179 yout.beginDocuments(); 1180 const size_t count = DocumentListTraits<T>::size(yout, docList); 1181 for(size_t i=0; i < count; ++i) { 1182 if ( yout.preflightDocument(i) ) { 1183 yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true); 1184 yout.postflightDocument(); 1185 } 1186 } 1187 yout.endDocuments(); 1188 return yout; 1189 } 1190 1191 // Define non-member operator<< so that Output can stream out a map. 1192 template <typename T> 1193 inline 1194 typename std::enable_if<has_MappingTraits<T>::value, Output &>::type 1195 operator<<(Output &yout, T &map) { 1196 yout.beginDocuments(); 1197 if ( yout.preflightDocument(0) ) { 1198 yamlize(yout, map, true); 1199 yout.postflightDocument(); 1200 } 1201 yout.endDocuments(); 1202 return yout; 1203 } 1204 1205 // Define non-member operator<< so that Output can stream out a sequence. 1206 template <typename T> 1207 inline 1208 typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type 1209 operator<<(Output &yout, T &seq) { 1210 yout.beginDocuments(); 1211 if ( yout.preflightDocument(0) ) { 1212 yamlize(yout, seq, true); 1213 yout.postflightDocument(); 1214 } 1215 yout.endDocuments(); 1216 return yout; 1217 } 1218 1219 // Provide better error message about types missing a trait specialization 1220 template <typename T> 1221 inline 1222 typename std::enable_if<missingTraits<T>::value, Output &>::type 1223 operator<<(Output &yout, T &seq) { 1224 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1225 return yout; 1226 } 1227 1228 1229 } // namespace yaml 1230 } // namespace llvm 1231 1232 1233 /// Utility for declaring that a std::vector of a particular type 1234 /// should be considered a YAML sequence. 1235 #define LLVM_YAML_IS_SEQUENCE_VECTOR(_type) \ 1236 namespace llvm { \ 1237 namespace yaml { \ 1238 template<> \ 1239 struct SequenceTraits< std::vector<_type> > { \ 1240 static size_t size(IO &io, std::vector<_type> &seq) { \ 1241 return seq.size(); \ 1242 } \ 1243 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1244 if ( index >= seq.size() ) \ 1245 seq.resize(index+1); \ 1246 return seq[index]; \ 1247 } \ 1248 }; \ 1249 } \ 1250 } 1251 1252 /// Utility for declaring that a std::vector of a particular type 1253 /// should be considered a YAML flow sequence. 1254 #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type) \ 1255 namespace llvm { \ 1256 namespace yaml { \ 1257 template<> \ 1258 struct SequenceTraits< std::vector<_type> > { \ 1259 static size_t size(IO &io, std::vector<_type> &seq) { \ 1260 return seq.size(); \ 1261 } \ 1262 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1263 (void)flow; /* Remove this workaround after PR17897 is fixed */ \ 1264 if ( index >= seq.size() ) \ 1265 seq.resize(index+1); \ 1266 return seq[index]; \ 1267 } \ 1268 static const bool flow = true; \ 1269 }; \ 1270 } \ 1271 } 1272 1273 /// Utility for declaring that a std::vector of a particular type 1274 /// should be considered a YAML document list. 1275 #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ 1276 namespace llvm { \ 1277 namespace yaml { \ 1278 template<> \ 1279 struct DocumentListTraits< std::vector<_type> > { \ 1280 static size_t size(IO &io, std::vector<_type> &seq) { \ 1281 return seq.size(); \ 1282 } \ 1283 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1284 if ( index >= seq.size() ) \ 1285 seq.resize(index+1); \ 1286 return seq[index]; \ 1287 } \ 1288 }; \ 1289 } \ 1290 } 1291 1292 1293 1294 #endif // LLVM_SUPPORT_YAMLTRAITS_H 1295