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