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 29namespace llvm { 30namespace 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/// }; 43template<class T> 44struct 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/// }; 63template<typename T> 64struct 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/// }; 81template<typename T> 82struct 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/// }; 104template<typename T> 105struct 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/// }; 134template<typename T> 135struct 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. 148template<typename T> 149struct 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 157template <typename T, T> 158struct SameType; 159 160// Only used for better diagnostics of missing traits 161template <typename T> 162struct MissingTrait; 163 164 165 166// Test if ScalarEnumerationTraits<T> is defined on type T. 167template <class T> 168struct 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 178public: 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. 185template <class T> 186struct 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 196public: 197 static bool const value = (sizeof(test<ScalarBitSetTraits<T> >(nullptr)) == 1); 198}; 199 200 201// Test if ScalarTraits<T> is defined on type T. 202template <class T> 203struct 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 217public: 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. 224template <class T> 225struct 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 235public: 236 static bool const value = (sizeof(test<MappingTraits<T> >(nullptr)) == 1); 237}; 238 239// Test if MappingTraits<T>::validate() is defined on type T. 240template <class T> 241struct 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 251public: 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. 258template <class T> 259struct 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 269public: 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. 277template <typename T, bool Enabled = std::is_class<T>::value> 278class has_FlowTraits 279{ 280public: 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. 287template <class T> 288struct 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 299public: 300 static bool const value = sizeof(f<Derived>(nullptr)) == 2; 301}; 302 303 304 305// Test if SequenceTraits<T> is defined on type T 306template<typename T> 307struct has_SequenceTraits : public std::integral_constant<bool, 308 has_SequenceMethodTraits<T>::value > { }; 309 310 311// Test if DocumentListTraits<T> is defined on type T 312template <class T> 313struct 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 323public: 324 static bool const value = (sizeof(test<DocumentListTraits<T> >(nullptr))==1); 325}; 326 327inline 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 356inline 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 369inline bool isNull(StringRef S) { 370 return S.equals("null") || S.equals("Null") || S.equals("NULL") || 371 S.equals("~"); 372} 373 374inline 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 379inline 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 404template<typename T> 405struct 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 413template<typename T> 414struct validatedMappingTraits : public std::integral_constant<bool, 415 has_MappingTraits<T>::value 416 && has_MappingValidateTraits<T>::value> {}; 417 418template<typename T> 419struct unvalidatedMappingTraits : public std::integral_constant<bool, 420 has_MappingTraits<T>::value 421 && !has_MappingValidateTraits<T>::value> {}; 422// Base class for Input and Output. 423class IO { 424public: 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 536private: 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 584private: 585 void *Ctxt; 586}; 587 588 589 590template<typename T> 591typename std::enable_if<has_ScalarEnumerationTraits<T>::value,void>::type 592yamlize(IO &io, T &Val, bool) { 593 io.beginEnumScalar(); 594 ScalarEnumerationTraits<T>::enumeration(io, Val); 595 io.endEnumScalar(); 596} 597 598template<typename T> 599typename std::enable_if<has_ScalarBitSetTraits<T>::value,void>::type 600yamlize(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 611template<typename T> 612typename std::enable_if<has_ScalarTraits<T>::value,void>::type 613yamlize(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 632template<typename T> 633typename std::enable_if<validatedMappingTraits<T>::value, void>::type 634yamlize(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 652template<typename T> 653typename std::enable_if<unvalidatedMappingTraits<T>::value, void>::type 654yamlize(IO &io, T &Val, bool) { 655 io.beginMapping(); 656 MappingTraits<T>::mapping(io, Val); 657 io.endMapping(); 658} 659 660template<typename T> 661typename std::enable_if<missingTraits<T>::value, void>::type 662yamlize(IO &io, T &Val, bool) { 663 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)]; 664} 665 666template<typename T> 667typename std::enable_if<has_SequenceTraits<T>::value,void>::type 668yamlize(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 696template<> 697struct 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 703template<> 704struct 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 710template<> 711struct 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 717template<> 718struct 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 724template<> 725struct 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 731template<> 732struct 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 738template<> 739struct 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 745template<> 746struct 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 752template<> 753struct 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 759template<> 760struct 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 766template<> 767struct 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 773template<> 774struct 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 780template<> 781struct 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. 791template <typename TNorm, typename TFinal> 792struct 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 812private: 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. 825template <typename TNorm, typename TFinal> 826struct 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 848private: 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/// 871class Input : public IO { 872public: 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 885private: 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 981public: 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 987private: 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/// 1006class Output : public IO { 1007public: 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; 1034public: 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 1042private: 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/// 1092LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8) 1093LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16) 1094LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32) 1095LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) 1096 1097 1098template<> 1099struct 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 1105template<> 1106struct 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 1112template<> 1113struct 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 1119template<> 1120struct 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. 1128template <typename T> 1129inline 1130typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type 1131operator>>(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. 1144template <typename T> 1145inline 1146typename std::enable_if<has_MappingTraits<T>::value, Input &>::type 1147operator>>(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. 1155template <typename T> 1156inline 1157typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type 1158operator>>(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 1165template <typename T> 1166inline 1167typename std::enable_if<missingTraits<T>::value, Input &>::type 1168operator>>(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. 1175template <typename T> 1176inline 1177typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type 1178operator<<(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. 1192template <typename T> 1193inline 1194typename std::enable_if<has_MappingTraits<T>::value, Output &>::type 1195operator<<(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. 1206template <typename T> 1207inline 1208typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type 1209operator<<(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 1220template <typename T> 1221inline 1222typename std::enable_if<missingTraits<T>::value, Output &>::type 1223operator<<(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