1165 lines · cpp
1//===- lib/Support/YAMLTraits.cpp -----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/YAMLTraits.h"10#include "llvm/ADT/STLExtras.h"11#include "llvm/ADT/SmallString.h"12#include "llvm/ADT/StringExtras.h"13#include "llvm/ADT/StringRef.h"14#include "llvm/ADT/Twine.h"15#include "llvm/Support/Casting.h"16#include "llvm/Support/Errc.h"17#include "llvm/Support/ErrorHandling.h"18#include "llvm/Support/Format.h"19#include "llvm/Support/LineIterator.h"20#include "llvm/Support/MemoryBuffer.h"21#include "llvm/Support/VersionTuple.h"22#include "llvm/Support/YAMLParser.h"23#include "llvm/Support/raw_ostream.h"24#include <cassert>25#include <cstdint>26#include <cstring>27#include <string>28#include <vector>29 30using namespace llvm;31using namespace yaml;32 33//===----------------------------------------------------------------------===//34// IO35//===----------------------------------------------------------------------===//36 37IO::IO(void *Context) : Ctxt(Context) {}38 39IO::~IO() = default;40 41void *IO::getContext() const {42 return Ctxt;43}44 45void IO::setContext(void *Context) {46 Ctxt = Context;47}48 49void IO::setAllowUnknownKeys(bool Allow) {50 llvm_unreachable("Only supported for Input");51}52 53//===----------------------------------------------------------------------===//54// Input55//===----------------------------------------------------------------------===//56 57Input::Input(StringRef InputContent, void *Ctxt,58 SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt)59 : IO(Ctxt), Strm(new Stream(InputContent, SrcMgr, false, &EC)) {60 if (DiagHandler)61 SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt);62 DocIterator = Strm->begin();63}64 65Input::Input(MemoryBufferRef Input, void *Ctxt,66 SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt)67 : IO(Ctxt), Strm(new Stream(Input, SrcMgr, false, &EC)) {68 if (DiagHandler)69 SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt);70 DocIterator = Strm->begin();71}72 73Input::~Input() = default;74 75std::error_code Input::error() { return EC; }76 77bool Input::outputting() const {78 return false;79}80 81bool Input::setCurrentDocument() {82 if (DocIterator != Strm->end()) {83 Node *N = DocIterator->getRoot();84 if (!N) {85 EC = make_error_code(errc::invalid_argument);86 return false;87 }88 89 if (isa<NullNode>(N)) {90 // Empty files are allowed and ignored91 ++DocIterator;92 return setCurrentDocument();93 }94 releaseHNodeBuffers();95 TopNode = createHNodes(N);96 CurrentNode = TopNode;97 return true;98 }99 return false;100}101 102bool Input::nextDocument() {103 return ++DocIterator != Strm->end();104}105 106const Node *Input::getCurrentNode() const {107 return CurrentNode ? CurrentNode->_node : nullptr;108}109 110bool Input::mapTag(StringRef Tag, bool Default) {111 // CurrentNode can be null if setCurrentDocument() was unable to112 // parse the document because it was invalid or empty.113 if (!CurrentNode)114 return false;115 116 std::string foundTag = CurrentNode->_node->getVerbatimTag();117 if (foundTag.empty()) {118 // If no tag found and 'Tag' is the default, say it was found.119 return Default;120 }121 // Return true iff found tag matches supplied tag.122 return Tag == foundTag;123}124 125void Input::beginMapping() {126 if (EC)127 return;128 // CurrentNode can be null if the document is empty.129 MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode);130 if (MN) {131 MN->ValidKeys.clear();132 }133}134 135std::vector<StringRef> Input::keys() {136 MapHNode *MN = dyn_cast<MapHNode>(CurrentNode);137 std::vector<StringRef> Ret;138 if (!MN) {139 setError(CurrentNode, "not a mapping");140 return Ret;141 }142 for (auto &P : MN->Mapping)143 Ret.push_back(P.first());144 return Ret;145}146 147bool Input::preflightKey(StringRef Key, bool Required, bool, bool &UseDefault,148 void *&SaveInfo) {149 UseDefault = false;150 if (EC)151 return false;152 153 // CurrentNode is null for empty documents, which is an error in case required154 // nodes are present.155 if (!CurrentNode) {156 if (Required)157 EC = make_error_code(errc::invalid_argument);158 else159 UseDefault = true;160 return false;161 }162 163 MapHNode *MN = dyn_cast<MapHNode>(CurrentNode);164 if (!MN) {165 if (Required || !isa<EmptyHNode>(CurrentNode))166 setError(CurrentNode, "not a mapping");167 else168 UseDefault = true;169 return false;170 }171 MN->ValidKeys.push_back(Key.str());172 HNode *Value = MN->Mapping[Key].first;173 if (!Value) {174 if (Required)175 setError(CurrentNode, Twine("missing required key '") + Key + "'");176 else177 UseDefault = true;178 return false;179 }180 SaveInfo = CurrentNode;181 CurrentNode = Value;182 return true;183}184 185void Input::postflightKey(void *saveInfo) {186 CurrentNode = reinterpret_cast<HNode *>(saveInfo);187}188 189void Input::endMapping() {190 if (EC)191 return;192 // CurrentNode can be null if the document is empty.193 MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode);194 if (!MN)195 return;196 for (const auto &NN : MN->Mapping) {197 if (!is_contained(MN->ValidKeys, NN.first())) {198 const SMRange &ReportLoc = NN.second.second;199 if (!AllowUnknownKeys) {200 setError(ReportLoc, Twine("unknown key '") + NN.first() + "'");201 break;202 } else203 reportWarning(ReportLoc, Twine("unknown key '") + NN.first() + "'");204 }205 }206}207 208void Input::beginFlowMapping() { beginMapping(); }209 210void Input::endFlowMapping() { endMapping(); }211 212unsigned Input::beginSequence() {213 if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode))214 return SQ->Entries.size();215 if (isa<EmptyHNode>(CurrentNode))216 return 0;217 // Treat case where there's a scalar "null" value as an empty sequence.218 if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {219 if (isNull(SN->value()))220 return 0;221 }222 // Any other type of HNode is an error.223 setError(CurrentNode, "not a sequence");224 return 0;225}226 227void Input::endSequence() {228}229 230bool Input::preflightElement(unsigned Index, void *&SaveInfo) {231 if (EC)232 return false;233 if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {234 SaveInfo = CurrentNode;235 CurrentNode = SQ->Entries[Index];236 return true;237 }238 return false;239}240 241void Input::postflightElement(void *SaveInfo) {242 CurrentNode = reinterpret_cast<HNode *>(SaveInfo);243}244 245unsigned Input::beginFlowSequence() { return beginSequence(); }246 247bool Input::preflightFlowElement(unsigned index, void *&SaveInfo) {248 if (EC)249 return false;250 if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {251 SaveInfo = CurrentNode;252 CurrentNode = SQ->Entries[index];253 return true;254 }255 return false;256}257 258void Input::postflightFlowElement(void *SaveInfo) {259 CurrentNode = reinterpret_cast<HNode *>(SaveInfo);260}261 262void Input::endFlowSequence() {263}264 265void Input::beginEnumScalar() {266 ScalarMatchFound = false;267}268 269bool Input::matchEnumScalar(StringRef Str, bool) {270 if (ScalarMatchFound)271 return false;272 if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {273 if (SN->value() == Str) {274 ScalarMatchFound = true;275 return true;276 }277 }278 return false;279}280 281bool Input::matchEnumFallback() {282 if (ScalarMatchFound)283 return false;284 ScalarMatchFound = true;285 return true;286}287 288void Input::endEnumScalar() {289 if (!ScalarMatchFound) {290 setError(CurrentNode, "unknown enumerated scalar");291 }292}293 294bool Input::beginBitSetScalar(bool &DoClear) {295 BitValuesUsed.clear();296 if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {297 BitValuesUsed.resize(SQ->Entries.size());298 } else {299 setError(CurrentNode, "expected sequence of bit values");300 }301 DoClear = true;302 return true;303}304 305bool Input::bitSetMatch(StringRef Str, bool) {306 if (EC)307 return false;308 if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {309 unsigned Index = 0;310 for (auto &N : SQ->Entries) {311 if (ScalarHNode *SN = dyn_cast<ScalarHNode>(N)) {312 if (SN->value() == Str) {313 BitValuesUsed[Index] = true;314 return true;315 }316 } else {317 setError(CurrentNode, "unexpected scalar in sequence of bit values");318 }319 ++Index;320 }321 } else {322 setError(CurrentNode, "expected sequence of bit values");323 }324 return false;325}326 327void Input::endBitSetScalar() {328 if (EC)329 return;330 if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {331 assert(BitValuesUsed.size() == SQ->Entries.size());332 for (unsigned i = 0; i < SQ->Entries.size(); ++i) {333 if (!BitValuesUsed[i]) {334 setError(SQ->Entries[i], "unknown bit value");335 return;336 }337 }338 }339}340 341void Input::scalarString(StringRef &S, QuotingType) {342 if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {343 S = SN->value();344 } else {345 setError(CurrentNode, "unexpected scalar");346 }347}348 349void Input::blockScalarString(StringRef &S) { scalarString(S, QuotingType::None); }350 351void Input::scalarTag(std::string &Tag) {352 Tag = CurrentNode->_node->getVerbatimTag();353}354 355void Input::setError(HNode *hnode, const Twine &message) {356 assert(hnode && "HNode must not be NULL");357 setError(hnode->_node, message);358}359 360NodeKind Input::getNodeKind() {361 if (isa<ScalarHNode>(CurrentNode))362 return NodeKind::Scalar;363 else if (isa<MapHNode>(CurrentNode))364 return NodeKind::Map;365 else if (isa<SequenceHNode>(CurrentNode))366 return NodeKind::Sequence;367 llvm_unreachable("Unsupported node kind");368}369 370void Input::setError(Node *node, const Twine &message) {371 Strm->printError(node, message);372 EC = make_error_code(errc::invalid_argument);373}374 375void Input::setError(const SMRange &range, const Twine &message) {376 Strm->printError(range, message);377 EC = make_error_code(errc::invalid_argument);378}379 380void Input::reportWarning(HNode *hnode, const Twine &message) {381 assert(hnode && "HNode must not be NULL");382 Strm->printError(hnode->_node, message, SourceMgr::DK_Warning);383}384 385void Input::reportWarning(Node *node, const Twine &message) {386 Strm->printError(node, message, SourceMgr::DK_Warning);387}388 389void Input::reportWarning(const SMRange &range, const Twine &message) {390 Strm->printError(range, message, SourceMgr::DK_Warning);391}392 393void Input::releaseHNodeBuffers() {394 EmptyHNodeAllocator.DestroyAll();395 ScalarHNodeAllocator.DestroyAll();396 SequenceHNodeAllocator.DestroyAll();397 MapHNodeAllocator.DestroyAll();398}399 400Input::HNode *Input::createHNodes(Node *N) {401 SmallString<128> StringStorage;402 switch (N->getType()) {403 case Node::NK_Scalar: {404 ScalarNode *SN = dyn_cast<ScalarNode>(N);405 StringRef KeyStr = SN->getValue(StringStorage);406 if (!StringStorage.empty()) {407 // Copy string to permanent storage408 KeyStr = StringStorage.str().copy(StringAllocator);409 }410 return new (ScalarHNodeAllocator.Allocate()) ScalarHNode(N, KeyStr);411 }412 case Node::NK_BlockScalar: {413 BlockScalarNode *BSN = dyn_cast<BlockScalarNode>(N);414 StringRef ValueCopy = BSN->getValue().copy(StringAllocator);415 return new (ScalarHNodeAllocator.Allocate()) ScalarHNode(N, ValueCopy);416 }417 case Node::NK_Sequence: {418 SequenceNode *SQ = dyn_cast<SequenceNode>(N);419 auto SQHNode = new (SequenceHNodeAllocator.Allocate()) SequenceHNode(N);420 for (Node &SN : *SQ) {421 auto Entry = createHNodes(&SN);422 if (EC)423 break;424 SQHNode->Entries.push_back(Entry);425 }426 return SQHNode;427 }428 case Node::NK_Mapping: {429 MappingNode *Map = dyn_cast<MappingNode>(N);430 auto mapHNode = new (MapHNodeAllocator.Allocate()) MapHNode(N);431 for (KeyValueNode &KVN : *Map) {432 Node *KeyNode = KVN.getKey();433 ScalarNode *Key = dyn_cast_or_null<ScalarNode>(KeyNode);434 Node *Value = KVN.getValue();435 if (!Key || !Value) {436 if (!Key)437 setError(KeyNode, "Map key must be a scalar");438 if (!Value)439 setError(KeyNode, "Map value must not be empty");440 break;441 }442 StringStorage.clear();443 StringRef KeyStr = Key->getValue(StringStorage);444 if (!StringStorage.empty()) {445 // Copy string to permanent storage446 KeyStr = StringStorage.str().copy(StringAllocator);447 }448 if (mapHNode->Mapping.count(KeyStr))449 // From YAML spec: "The content of a mapping node is an unordered set of450 // key/value node pairs, with the restriction that each of the keys is451 // unique."452 setError(KeyNode, Twine("duplicated mapping key '") + KeyStr + "'");453 auto ValueHNode = createHNodes(Value);454 if (EC)455 break;456 mapHNode->Mapping[KeyStr] =457 std::make_pair(std::move(ValueHNode), KeyNode->getSourceRange());458 }459 return std::move(mapHNode);460 }461 case Node::NK_Null:462 return new (EmptyHNodeAllocator.Allocate()) EmptyHNode(N);463 default:464 setError(N, "unknown node kind");465 return nullptr;466 }467}468 469void Input::setError(const Twine &Message) {470 setError(CurrentNode, Message);471}472 473void Input::setAllowUnknownKeys(bool Allow) { AllowUnknownKeys = Allow; }474 475bool Input::canElideEmptySequence() {476 return false;477}478 479//===----------------------------------------------------------------------===//480// Output481//===----------------------------------------------------------------------===//482 483Output::Output(raw_ostream &yout, void *context, int WrapColumn)484 : IO(context), Out(yout), WrapColumn(WrapColumn) {}485 486Output::~Output() = default;487 488bool Output::outputting() const {489 return true;490}491 492void Output::beginMapping() {493 StateStack.push_back(inMapFirstKey);494 PaddingBeforeContainer = Padding;495 Padding = "\n";496}497 498bool Output::mapTag(StringRef Tag, bool Use) {499 if (Use) {500 // If this tag is being written inside a sequence we should write the start501 // of the sequence before writing the tag, otherwise the tag won't be502 // attached to the element in the sequence, but rather the sequence itself.503 bool SequenceElement = false;504 if (StateStack.size() > 1) {505 auto &E = StateStack[StateStack.size() - 2];506 SequenceElement = inSeqAnyElement(E) || inFlowSeqAnyElement(E);507 }508 if (SequenceElement && StateStack.back() == inMapFirstKey) {509 newLineCheck();510 } else {511 output(" ");512 }513 output(Tag);514 if (SequenceElement) {515 // If we're writing the tag during the first element of a map, the tag516 // takes the place of the first element in the sequence.517 if (StateStack.back() == inMapFirstKey) {518 StateStack.pop_back();519 StateStack.push_back(inMapOtherKey);520 }521 // Tags inside maps in sequences should act as keys in the map from a522 // formatting perspective, so we always want a newline in a sequence.523 Padding = "\n";524 }525 }526 return Use;527}528 529void Output::endMapping() {530 // If we did not map anything, we should explicitly emit an empty map531 if (StateStack.back() == inMapFirstKey) {532 Padding = PaddingBeforeContainer;533 newLineCheck();534 output("{}");535 Padding = "\n";536 }537 StateStack.pop_back();538}539 540std::vector<StringRef> Output::keys() {541 report_fatal_error("invalid call");542}543 544bool Output::preflightKey(StringRef Key, bool Required, bool SameAsDefault,545 bool &UseDefault, void *&SaveInfo) {546 UseDefault = false;547 SaveInfo = nullptr;548 if (Required || !SameAsDefault || WriteDefaultValues) {549 auto State = StateStack.back();550 if (State == inFlowMapFirstKey || State == inFlowMapOtherKey) {551 flowKey(Key);552 } else {553 newLineCheck();554 paddedKey(Key);555 }556 return true;557 }558 return false;559}560 561void Output::postflightKey(void *) {562 if (StateStack.back() == inMapFirstKey) {563 StateStack.pop_back();564 StateStack.push_back(inMapOtherKey);565 } else if (StateStack.back() == inFlowMapFirstKey) {566 StateStack.pop_back();567 StateStack.push_back(inFlowMapOtherKey);568 }569}570 571void Output::beginFlowMapping() {572 StateStack.push_back(inFlowMapFirstKey);573 newLineCheck();574 ColumnAtMapFlowStart = Column;575 output("{ ");576}577 578void Output::endFlowMapping() {579 StateStack.pop_back();580 outputUpToEndOfLine(" }");581}582 583void Output::beginDocuments() {584 outputUpToEndOfLine("---");585}586 587bool Output::preflightDocument(unsigned index) {588 if (index > 0)589 outputUpToEndOfLine("\n---");590 return true;591}592 593void Output::postflightDocument() {594}595 596void Output::endDocuments() {597 output("\n...\n");598}599 600unsigned Output::beginSequence() {601 StateStack.push_back(inSeqFirstElement);602 PaddingBeforeContainer = Padding;603 Padding = "\n";604 return 0;605}606 607void Output::endSequence() {608 // If we did not emit anything, we should explicitly emit an empty sequence609 if (StateStack.back() == inSeqFirstElement) {610 Padding = PaddingBeforeContainer;611 newLineCheck(/*EmptySequence=*/true);612 output("[]");613 Padding = "\n";614 }615 StateStack.pop_back();616}617 618bool Output::preflightElement(unsigned, void *&SaveInfo) {619 SaveInfo = nullptr;620 return true;621}622 623void Output::postflightElement(void *) {624 if (StateStack.back() == inSeqFirstElement) {625 StateStack.pop_back();626 StateStack.push_back(inSeqOtherElement);627 } else if (StateStack.back() == inFlowSeqFirstElement) {628 StateStack.pop_back();629 StateStack.push_back(inFlowSeqOtherElement);630 }631}632 633unsigned Output::beginFlowSequence() {634 StateStack.push_back(inFlowSeqFirstElement);635 newLineCheck();636 ColumnAtFlowStart = Column;637 output("[ ");638 NeedFlowSequenceComma = false;639 return 0;640}641 642void Output::endFlowSequence() {643 StateStack.pop_back();644 outputUpToEndOfLine(" ]");645}646 647bool Output::preflightFlowElement(unsigned, void *&SaveInfo) {648 if (NeedFlowSequenceComma)649 output(", ");650 if (WrapColumn && Column > WrapColumn) {651 output("\n");652 for (int i = 0; i < ColumnAtFlowStart; ++i)653 output(" ");654 Column = ColumnAtFlowStart;655 output(" ");656 }657 SaveInfo = nullptr;658 return true;659}660 661void Output::postflightFlowElement(void *) {662 NeedFlowSequenceComma = true;663}664 665void Output::beginEnumScalar() {666 EnumerationMatchFound = false;667}668 669bool Output::matchEnumScalar(StringRef Str, bool Match) {670 if (Match && !EnumerationMatchFound) {671 newLineCheck();672 outputUpToEndOfLine(Str);673 EnumerationMatchFound = true;674 }675 return false;676}677 678bool Output::matchEnumFallback() {679 if (EnumerationMatchFound)680 return false;681 EnumerationMatchFound = true;682 return true;683}684 685void Output::endEnumScalar() {686 if (!EnumerationMatchFound)687 llvm_unreachable("bad runtime enum value");688}689 690bool Output::beginBitSetScalar(bool &DoClear) {691 newLineCheck();692 output("[ ");693 NeedBitValueComma = false;694 DoClear = false;695 return true;696}697 698bool Output::bitSetMatch(StringRef Str, bool Matches) {699 if (Matches) {700 if (NeedBitValueComma)701 output(", ");702 output(Str);703 NeedBitValueComma = true;704 }705 return false;706}707 708void Output::endBitSetScalar() {709 outputUpToEndOfLine(" ]");710}711 712void Output::scalarString(StringRef &S, QuotingType MustQuote) {713 newLineCheck();714 if (S.empty()) {715 // Print '' for the empty string because leaving the field empty is not716 // allowed.717 outputUpToEndOfLine("''");718 return;719 }720 output(S, MustQuote);721 outputUpToEndOfLine("");722}723 724void Output::blockScalarString(StringRef &S) {725 if (!StateStack.empty())726 newLineCheck();727 output(" |");728 729 unsigned Indent = StateStack.empty() ? 1 : StateStack.size();730 731 auto Buffer = MemoryBuffer::getMemBuffer(S, "", false);732 for (line_iterator Lines(*Buffer, false); !Lines.is_at_end(); ++Lines) {733 outputNewLine();734 for (unsigned I = 0; I < Indent; ++I) {735 output(" ");736 }737 output(*Lines);738 }739 outputUpToEndOfLine("");740}741 742void Output::scalarTag(std::string &Tag) {743 if (Tag.empty())744 return;745 newLineCheck();746 output(Tag);747 output(" ");748}749 750void Output::setError(const Twine &message) {751}752 753std::error_code Output::error() { return {}; }754 755bool Output::canElideEmptySequence() {756 // Normally, with an optional key/value where the value is an empty sequence,757 // the whole key/value can be not written. But, that produces wrong yaml758 // if the key/value is the only thing in the map and the map is used in759 // a sequence. This detects if the this sequence is the first key/value760 // in map that itself is embedded in a sequence.761 if (StateStack.size() < 2)762 return true;763 if (StateStack.back() != inMapFirstKey)764 return true;765 return !inSeqAnyElement(StateStack[StateStack.size() - 2]);766}767 768void Output::output(StringRef s) {769 Column += s.size();770 Out << s;771}772 773void Output::output(StringRef S, QuotingType MustQuote) {774 if (MustQuote == QuotingType::None) {775 // Only quote if we must.776 output(S);777 return;778 }779 780 StringLiteral Quote = MustQuote == QuotingType::Single ? StringLiteral("'")781 : StringLiteral("\"");782 output(Quote); // Starting quote.783 784 // When using double-quoted strings (and only in that case), non-printable785 // characters may be present, and will be escaped using a variety of786 // unicode-scalar and special short-form escapes. This is handled in787 // yaml::escape.788 if (MustQuote == QuotingType::Double) {789 output(yaml::escape(S, /* EscapePrintable= */ false));790 output(Quote);791 return;792 }793 794 unsigned i = 0;795 unsigned j = 0;796 unsigned End = S.size();797 const char *Base = S.data();798 799 // When using single-quoted strings, any single quote ' must be doubled to be800 // escaped.801 while (j < End) {802 if (S[j] == '\'') { // Escape quotes.803 output(StringRef(&Base[i], j - i)); // "flush".804 output(StringLiteral("''")); // Print it as ''805 i = j + 1;806 }807 ++j;808 }809 output(StringRef(&Base[i], j - i));810 output(Quote); // Ending quote.811}812 813void Output::outputUpToEndOfLine(StringRef s) {814 output(s);815 if (StateStack.empty() || (!inFlowSeqAnyElement(StateStack.back()) &&816 !inFlowMapAnyKey(StateStack.back())))817 Padding = "\n";818}819 820void Output::outputNewLine() {821 Out << "\n";822 Column = 0;823}824 825// if seq at top, indent as if map, then add "- "826// if seq in middle, use "- " if firstKey, else use " "827//828 829void Output::newLineCheck(bool EmptySequence) {830 if (Padding != "\n") {831 output(Padding);832 Padding = {};833 return;834 }835 outputNewLine();836 Padding = {};837 838 if (StateStack.size() == 0 || EmptySequence)839 return;840 841 unsigned Indent = StateStack.size() - 1;842 bool PossiblyNestedSeq = false;843 auto I = StateStack.rbegin(), E = StateStack.rend();844 845 if (inSeqAnyElement(*I)) {846 PossiblyNestedSeq = true; // Not possibly but always.847 ++Indent;848 } else if (*I == inMapFirstKey || *I == inFlowMapFirstKey ||849 inFlowSeqAnyElement(*I)) {850 PossiblyNestedSeq = true;851 ++I; // Skip back().852 }853 854 unsigned OutputDashCount = 0;855 if (PossiblyNestedSeq) {856 // Count up consecutive inSeqFirstElement from the end, unless857 // inSeqFirstElement is the top of nested sequence.858 while (I != E) {859 // Don't count the top of nested sequence.860 if (!inSeqAnyElement(*I))861 break;862 863 ++OutputDashCount;864 865 // Stop counting if consecutive inSeqFirstElement ends.866 if (*I++ != inSeqFirstElement)867 break;868 }869 }870 871 for (unsigned I = OutputDashCount; I < Indent; ++I)872 output(" ");873 874 for (unsigned I = 0; I < OutputDashCount; ++I)875 output("- ");876}877 878void Output::paddedKey(StringRef key) {879 output(key, needsQuotes(key, false));880 output(":");881 const char *spaces = " ";882 if (key.size() < strlen(spaces))883 Padding = &spaces[key.size()];884 else885 Padding = " ";886}887 888void Output::flowKey(StringRef Key) {889 if (StateStack.back() == inFlowMapOtherKey)890 output(", ");891 if (WrapColumn && Column > WrapColumn) {892 output("\n");893 for (int I = 0; I < ColumnAtMapFlowStart; ++I)894 output(" ");895 Column = ColumnAtMapFlowStart;896 output(" ");897 }898 output(Key, needsQuotes(Key, false));899 output(": ");900}901 902NodeKind Output::getNodeKind() { report_fatal_error("invalid call"); }903 904bool Output::inSeqAnyElement(InState State) {905 return State == inSeqFirstElement || State == inSeqOtherElement;906}907 908bool Output::inFlowSeqAnyElement(InState State) {909 return State == inFlowSeqFirstElement || State == inFlowSeqOtherElement;910}911 912bool Output::inMapAnyKey(InState State) {913 return State == inMapFirstKey || State == inMapOtherKey;914}915 916bool Output::inFlowMapAnyKey(InState State) {917 return State == inFlowMapFirstKey || State == inFlowMapOtherKey;918}919 920//===----------------------------------------------------------------------===//921// traits for built-in types922//===----------------------------------------------------------------------===//923 924void ScalarTraits<bool>::output(const bool &Val, void *, raw_ostream &Out) {925 Out << (Val ? "true" : "false");926}927 928StringRef ScalarTraits<bool>::input(StringRef Scalar, void *, bool &Val) {929 if (std::optional<bool> Parsed = parseBool(Scalar)) {930 Val = *Parsed;931 return StringRef();932 }933 return "invalid boolean";934}935 936void ScalarTraits<StringRef>::output(const StringRef &Val, void *,937 raw_ostream &Out) {938 Out << Val;939}940 941StringRef ScalarTraits<StringRef>::input(StringRef Scalar, void *,942 StringRef &Val) {943 Val = Scalar;944 return StringRef();945}946 947void ScalarTraits<std::string>::output(const std::string &Val, void *,948 raw_ostream &Out) {949 Out << Val;950}951 952StringRef ScalarTraits<std::string>::input(StringRef Scalar, void *,953 std::string &Val) {954 Val = Scalar.str();955 return StringRef();956}957 958void ScalarTraits<uint8_t>::output(const uint8_t &Val, void *,959 raw_ostream &Out) {960 // use temp uin32_t because ostream thinks uint8_t is a character961 uint32_t Num = Val;962 Out << Num;963}964 965StringRef ScalarTraits<uint8_t>::input(StringRef Scalar, void *, uint8_t &Val) {966 unsigned long long n;967 if (getAsUnsignedInteger(Scalar, 0, n))968 return "invalid number";969 if (n > 0xFF)970 return "out of range number";971 Val = n;972 return StringRef();973}974 975void ScalarTraits<uint16_t>::output(const uint16_t &Val, void *,976 raw_ostream &Out) {977 Out << Val;978}979 980StringRef ScalarTraits<uint16_t>::input(StringRef Scalar, void *,981 uint16_t &Val) {982 unsigned long long n;983 if (getAsUnsignedInteger(Scalar, 0, n))984 return "invalid number";985 if (n > 0xFFFF)986 return "out of range number";987 Val = n;988 return StringRef();989}990 991void ScalarTraits<uint32_t>::output(const uint32_t &Val, void *,992 raw_ostream &Out) {993 Out << Val;994}995 996StringRef ScalarTraits<uint32_t>::input(StringRef Scalar, void *,997 uint32_t &Val) {998 unsigned long long n;999 if (getAsUnsignedInteger(Scalar, 0, n))1000 return "invalid number";1001 if (n > 0xFFFFFFFFUL)1002 return "out of range number";1003 Val = n;1004 return StringRef();1005}1006 1007void ScalarTraits<uint64_t>::output(const uint64_t &Val, void *,1008 raw_ostream &Out) {1009 Out << Val;1010}1011 1012StringRef ScalarTraits<uint64_t>::input(StringRef Scalar, void *,1013 uint64_t &Val) {1014 unsigned long long N;1015 if (getAsUnsignedInteger(Scalar, 0, N))1016 return "invalid number";1017 Val = N;1018 return StringRef();1019}1020 1021void ScalarTraits<int8_t>::output(const int8_t &Val, void *, raw_ostream &Out) {1022 // use temp in32_t because ostream thinks int8_t is a character1023 int32_t Num = Val;1024 Out << Num;1025}1026 1027StringRef ScalarTraits<int8_t>::input(StringRef Scalar, void *, int8_t &Val) {1028 long long N;1029 if (getAsSignedInteger(Scalar, 0, N))1030 return "invalid number";1031 if ((N > 127) || (N < -128))1032 return "out of range number";1033 Val = N;1034 return StringRef();1035}1036 1037void ScalarTraits<int16_t>::output(const int16_t &Val, void *,1038 raw_ostream &Out) {1039 Out << Val;1040}1041 1042StringRef ScalarTraits<int16_t>::input(StringRef Scalar, void *, int16_t &Val) {1043 long long N;1044 if (getAsSignedInteger(Scalar, 0, N))1045 return "invalid number";1046 if ((N > INT16_MAX) || (N < INT16_MIN))1047 return "out of range number";1048 Val = N;1049 return StringRef();1050}1051 1052void ScalarTraits<int32_t>::output(const int32_t &Val, void *,1053 raw_ostream &Out) {1054 Out << Val;1055}1056 1057StringRef ScalarTraits<int32_t>::input(StringRef Scalar, void *, int32_t &Val) {1058 long long N;1059 if (getAsSignedInteger(Scalar, 0, N))1060 return "invalid number";1061 if ((N > INT32_MAX) || (N < INT32_MIN))1062 return "out of range number";1063 Val = N;1064 return StringRef();1065}1066 1067void ScalarTraits<int64_t>::output(const int64_t &Val, void *,1068 raw_ostream &Out) {1069 Out << Val;1070}1071 1072StringRef ScalarTraits<int64_t>::input(StringRef Scalar, void *, int64_t &Val) {1073 long long N;1074 if (getAsSignedInteger(Scalar, 0, N))1075 return "invalid number";1076 Val = N;1077 return StringRef();1078}1079 1080void ScalarTraits<double>::output(const double &Val, void *, raw_ostream &Out) {1081 Out << format("%g", Val);1082}1083 1084StringRef ScalarTraits<double>::input(StringRef Scalar, void *, double &Val) {1085 if (to_float(Scalar, Val))1086 return StringRef();1087 return "invalid floating point number";1088}1089 1090void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) {1091 Out << format("%g", Val);1092}1093 1094StringRef ScalarTraits<float>::input(StringRef Scalar, void *, float &Val) {1095 if (to_float(Scalar, Val))1096 return StringRef();1097 return "invalid floating point number";1098}1099 1100void ScalarTraits<Hex8>::output(const Hex8 &Val, void *, raw_ostream &Out) {1101 Out << format("0x%" PRIX8, (uint8_t)Val);1102}1103 1104StringRef ScalarTraits<Hex8>::input(StringRef Scalar, void *, Hex8 &Val) {1105 unsigned long long n;1106 if (getAsUnsignedInteger(Scalar, 0, n))1107 return "invalid hex8 number";1108 if (n > 0xFF)1109 return "out of range hex8 number";1110 Val = n;1111 return StringRef();1112}1113 1114void ScalarTraits<Hex16>::output(const Hex16 &Val, void *, raw_ostream &Out) {1115 Out << format("0x%" PRIX16, (uint16_t)Val);1116}1117 1118StringRef ScalarTraits<Hex16>::input(StringRef Scalar, void *, Hex16 &Val) {1119 unsigned long long n;1120 if (getAsUnsignedInteger(Scalar, 0, n))1121 return "invalid hex16 number";1122 if (n > 0xFFFF)1123 return "out of range hex16 number";1124 Val = n;1125 return StringRef();1126}1127 1128void ScalarTraits<Hex32>::output(const Hex32 &Val, void *, raw_ostream &Out) {1129 Out << format("0x%" PRIX32, (uint32_t)Val);1130}1131 1132StringRef ScalarTraits<Hex32>::input(StringRef Scalar, void *, Hex32 &Val) {1133 unsigned long long n;1134 if (getAsUnsignedInteger(Scalar, 0, n))1135 return "invalid hex32 number";1136 if (n > 0xFFFFFFFFUL)1137 return "out of range hex32 number";1138 Val = n;1139 return StringRef();1140}1141 1142void ScalarTraits<Hex64>::output(const Hex64 &Val, void *, raw_ostream &Out) {1143 Out << format("0x%" PRIX64, (uint64_t)Val);1144}1145 1146StringRef ScalarTraits<Hex64>::input(StringRef Scalar, void *, Hex64 &Val) {1147 unsigned long long Num;1148 if (getAsUnsignedInteger(Scalar, 0, Num))1149 return "invalid hex64 number";1150 Val = Num;1151 return StringRef();1152}1153 1154void ScalarTraits<VersionTuple>::output(const VersionTuple &Val, void *,1155 llvm::raw_ostream &Out) {1156 Out << Val.getAsString();1157}1158 1159StringRef ScalarTraits<VersionTuple>::input(StringRef Scalar, void *,1160 VersionTuple &Val) {1161 if (Val.tryParse(Scalar))1162 return "invalid version format";1163 return StringRef();1164}1165