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/StringExtras.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 struct StrMappingInfo { 764 static StringRef getEmptyKey() { return StringRef(); } 765 static StringRef getTombstoneKey() { return StringRef(" ", 0); } 766 static unsigned getHashValue(StringRef const val) { 767 return llvm::HashString(val); } 768 static bool isEqual(StringRef const lhs, 769 StringRef const rhs) { return lhs.equals(rhs); } 770 }; 771 typedef llvm::DenseMap<StringRef, HNode*, StrMappingInfo> NameToNode; 772 773 bool isValidKey(StringRef key); 774 775 NameToNode Mapping; 776 llvm::SmallVector<const char*, 6> ValidKeys; 777 }; 778 779 class SequenceHNode : public HNode { 780 public: 781 SequenceHNode(Node *n) : HNode(n) { } 782 virtual ~SequenceHNode(); 783 784 static inline bool classof(const HNode *n) { 785 return SequenceNode::classof(n->_node); 786 } 787 static inline bool classof(const SequenceHNode *) { return true; } 788 789 std::vector<HNode*> Entries; 790 }; 791 792 Input::HNode *createHNodes(Node *node); 793 void setError(HNode *hnode, const Twine &message); 794 void setError(Node *node, const Twine &message); 795 796 797 public: 798 // These are only used by operator>>. They could be private 799 // if those templated things could be made friends. 800 bool setCurrentDocument(); 801 void nextDocument(); 802 803 private: 804 llvm::SourceMgr SrcMgr; // must be before Strm 805 OwningPtr<llvm::yaml::Stream> Strm; 806 OwningPtr<HNode> TopNode; 807 llvm::error_code EC; 808 llvm::BumpPtrAllocator StringAllocator; 809 llvm::yaml::document_iterator DocIterator; 810 std::vector<bool> BitValuesUsed; 811 HNode *CurrentNode; 812 bool ScalarMatchFound; 813 }; 814 815 816 817 818 /// 819 /// The Output class is used to generate a yaml document from in-memory structs 820 /// and vectors. 821 /// 822 class Output : public IO { 823 public: 824 Output(llvm::raw_ostream &, void *Ctxt=NULL); 825 virtual ~Output(); 826 827 virtual bool outputting(); 828 virtual void beginMapping(); 829 virtual void endMapping(); 830 virtual bool preflightKey(const char *key, bool, bool, bool &, void *&); 831 virtual void postflightKey(void *); 832 virtual unsigned beginSequence(); 833 virtual void endSequence(); 834 virtual bool preflightElement(unsigned, void *&); 835 virtual void postflightElement(void *); 836 virtual unsigned beginFlowSequence(); 837 virtual bool preflightFlowElement(unsigned, void *&); 838 virtual void postflightFlowElement(void *); 839 virtual void endFlowSequence(); 840 virtual void beginEnumScalar(); 841 virtual bool matchEnumScalar(const char*, bool); 842 virtual void endEnumScalar(); 843 virtual bool beginBitSetScalar(bool &); 844 virtual bool bitSetMatch(const char *, bool ); 845 virtual void endBitSetScalar(); 846 virtual void scalarString(StringRef &); 847 virtual void setError(const Twine &message); 848 849 public: 850 // These are only used by operator<<. They could be private 851 // if that templated operator could be made a friend. 852 void beginDocuments(); 853 bool preflightDocument(unsigned); 854 void postflightDocument(); 855 void endDocuments(); 856 857 private: 858 void output(StringRef s); 859 void outputUpToEndOfLine(StringRef s); 860 void newLineCheck(); 861 void outputNewLine(); 862 void paddedKey(StringRef key); 863 864 enum InState { inSeq, inFlowSeq, inMapFirstKey, inMapOtherKey }; 865 866 llvm::raw_ostream &Out; 867 SmallVector<InState, 8> StateStack; 868 int Column; 869 int ColumnAtFlowStart; 870 bool NeedBitValueComma; 871 bool NeedFlowSequenceComma; 872 bool EnumerationMatchFound; 873 bool NeedsNewLine; 874 }; 875 876 877 878 879 /// YAML I/O does conversion based on types. But often native data types 880 /// are just a typedef of built in intergral types (e.g. int). But the C++ 881 /// type matching system sees through the typedef and all the typedefed types 882 /// look like a built in type. This will cause the generic YAML I/O conversion 883 /// to be used. To provide better control over the YAML conversion, you can 884 /// use this macro instead of typedef. It will create a class with one field 885 /// and automatic conversion operators to and from the base type. 886 /// Based on BOOST_STRONG_TYPEDEF 887 #define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \ 888 struct _type { \ 889 _type() { } \ 890 _type(const _base v) : value(v) { } \ 891 _type(const _type &v) : value(v.value) {} \ 892 _type &operator=(const _type &rhs) { value = rhs.value; return *this; }\ 893 _type &operator=(const _base &rhs) { value = rhs; return *this; } \ 894 operator const _base & () const { return value; } \ 895 bool operator==(const _type &rhs) const { return value == rhs.value; } \ 896 bool operator==(const _base &rhs) const { return value == rhs; } \ 897 bool operator<(const _type &rhs) const { return value < rhs.value; } \ 898 _base value; \ 899 }; 900 901 902 903 /// 904 /// Use these types instead of uintXX_t in any mapping to have 905 /// its yaml output formatted as hexadecimal. 906 /// 907 LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) 908 LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) 909 LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) 910 LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) 911 912 913 template<> 914 struct ScalarTraits<Hex8> { 915 static void output(const Hex8 &, void*, llvm::raw_ostream &); 916 static StringRef input(StringRef, void*, Hex8 &); 917 }; 918 919 template<> 920 struct ScalarTraits<Hex16> { 921 static void output(const Hex16 &, void*, llvm::raw_ostream &); 922 static StringRef input(StringRef, void*, Hex16 &); 923 }; 924 925 template<> 926 struct ScalarTraits<Hex32> { 927 static void output(const Hex32 &, void*, llvm::raw_ostream &); 928 static StringRef input(StringRef, void*, Hex32 &); 929 }; 930 931 template<> 932 struct ScalarTraits<Hex64> { 933 static void output(const Hex64 &, void*, llvm::raw_ostream &); 934 static StringRef input(StringRef, void*, Hex64 &); 935 }; 936 937 938 // Define non-member operator>> so that Input can stream in a document list. 939 template <typename T> 940 inline 941 typename llvm::enable_if_c<has_DocumentListTraits<T>::value,Input &>::type 942 operator>>(Input &yin, T &docList) { 943 int i = 0; 944 while ( yin.setCurrentDocument() ) { 945 yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true); 946 if ( yin.error() ) 947 return yin; 948 yin.nextDocument(); 949 ++i; 950 } 951 return yin; 952 } 953 954 // Define non-member operator>> so that Input can stream in a map as a document. 955 template <typename T> 956 inline 957 typename llvm::enable_if_c<has_MappingTraits<T>::value,Input &>::type 958 operator>>(Input &yin, T &docMap) { 959 yin.setCurrentDocument(); 960 yamlize(yin, docMap, true); 961 return yin; 962 } 963 964 // Define non-member operator>> so that Input can stream in a sequence as 965 // a document. 966 template <typename T> 967 inline 968 typename llvm::enable_if_c<has_SequenceTraits<T>::value,Input &>::type 969 operator>>(Input &yin, T &docSeq) { 970 yin.setCurrentDocument(); 971 yamlize(yin, docSeq, true); 972 return yin; 973 } 974 975 // Provide better error message about types missing a trait specialization 976 template <typename T> 977 inline 978 typename llvm::enable_if_c<missingTraits<T>::value,Input &>::type 979 operator>>(Input &yin, T &docSeq) { 980 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 981 return yin; 982 } 983 984 985 // Define non-member operator<< so that Output can stream out document list. 986 template <typename T> 987 inline 988 typename llvm::enable_if_c<has_DocumentListTraits<T>::value,Output &>::type 989 operator<<(Output &yout, T &docList) { 990 yout.beginDocuments(); 991 const size_t count = DocumentListTraits<T>::size(yout, docList); 992 for(size_t i=0; i < count; ++i) { 993 if ( yout.preflightDocument(i) ) { 994 yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true); 995 yout.postflightDocument(); 996 } 997 } 998 yout.endDocuments(); 999 return yout; 1000 } 1001 1002 // Define non-member operator<< so that Output can stream out a map. 1003 template <typename T> 1004 inline 1005 typename llvm::enable_if_c<has_MappingTraits<T>::value,Output &>::type 1006 operator<<(Output &yout, T &map) { 1007 yout.beginDocuments(); 1008 if ( yout.preflightDocument(0) ) { 1009 yamlize(yout, map, true); 1010 yout.postflightDocument(); 1011 } 1012 yout.endDocuments(); 1013 return yout; 1014 } 1015 1016 // Define non-member operator<< so that Output can stream out a sequence. 1017 template <typename T> 1018 inline 1019 typename llvm::enable_if_c<has_SequenceTraits<T>::value,Output &>::type 1020 operator<<(Output &yout, T &seq) { 1021 yout.beginDocuments(); 1022 if ( yout.preflightDocument(0) ) { 1023 yamlize(yout, seq, true); 1024 yout.postflightDocument(); 1025 } 1026 yout.endDocuments(); 1027 return yout; 1028 } 1029 1030 // Provide better error message about types missing a trait specialization 1031 template <typename T> 1032 inline 1033 typename llvm::enable_if_c<missingTraits<T>::value,Output &>::type 1034 operator<<(Output &yout, T &seq) { 1035 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 1036 return yout; 1037 } 1038 1039 1040 } // namespace yaml 1041 } // namespace llvm 1042 1043 1044 /// Utility for declaring that a std::vector of a particular type 1045 /// should be considered a YAML sequence. 1046 #define LLVM_YAML_IS_SEQUENCE_VECTOR(_type) \ 1047 namespace llvm { \ 1048 namespace yaml { \ 1049 template<> \ 1050 struct SequenceTraits< std::vector<_type> > { \ 1051 static size_t size(IO &io, std::vector<_type> &seq) { \ 1052 return seq.size(); \ 1053 } \ 1054 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1055 if ( index >= seq.size() ) \ 1056 seq.resize(index+1); \ 1057 return seq[index]; \ 1058 } \ 1059 }; \ 1060 } \ 1061 } 1062 1063 /// Utility for declaring that a std::vector of a particular type 1064 /// should be considered a YAML flow sequence. 1065 #define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type) \ 1066 namespace llvm { \ 1067 namespace yaml { \ 1068 template<> \ 1069 struct SequenceTraits< std::vector<_type> > { \ 1070 static size_t size(IO &io, std::vector<_type> &seq) { \ 1071 return seq.size(); \ 1072 } \ 1073 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1074 if ( index >= seq.size() ) \ 1075 seq.resize(index+1); \ 1076 return seq[index]; \ 1077 } \ 1078 static const bool flow = true; \ 1079 }; \ 1080 } \ 1081 } 1082 1083 /// Utility for declaring that a std::vector of a particular type 1084 /// should be considered a YAML document list. 1085 #define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \ 1086 namespace llvm { \ 1087 namespace yaml { \ 1088 template<> \ 1089 struct DocumentListTraits< std::vector<_type> > { \ 1090 static size_t size(IO &io, std::vector<_type> &seq) { \ 1091 return seq.size(); \ 1092 } \ 1093 static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\ 1094 if ( index >= seq.size() ) \ 1095 seq.resize(index+1); \ 1096 return seq[index]; \ 1097 } \ 1098 }; \ 1099 } \ 1100 } 1101 1102 1103 1104 #endif // LLVM_SUPPORT_YAMLTRAITS_H 1105