X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FSupport%2FYAMLTraits.cpp;h=2aa6e9b7468333976e97d03919a7a09df41ffded;hb=ceb49e0185080711a45510fe5c3aca7ed8aa1f34;hp=8fcef40d243f4499364034eb38632cf288b79b8b;hpb=2b45dd58b22da40bb08e82d1564ccecca4a700f5;p=oota-llvm.git diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp index 8fcef40d243..2aa6e9b7468 100644 --- a/lib/Support/YAMLTraits.cpp +++ b/lib/Support/YAMLTraits.cpp @@ -8,12 +8,16 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/YAMLTraits.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" +#include "llvm/Support/LineIterator.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" +#include #include using namespace llvm; using namespace yaml; @@ -40,18 +44,29 @@ void IO::setContext(void *Context) { // Input //===----------------------------------------------------------------------===// -Input::Input(StringRef InputContent, void *Ctxt) : IO(Ctxt), CurrentNode(NULL) { - Strm = new Stream(InputContent, SrcMgr); +Input::Input(StringRef InputContent, + void *Ctxt, + SourceMgr::DiagHandlerTy DiagHandler, + void *DiagHandlerCtxt) + : IO(Ctxt), + Strm(new Stream(InputContent, SrcMgr)), + CurrentNode(nullptr) { + if (DiagHandler) + SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt); DocIterator = Strm->begin(); } -error_code Input::error() { - return EC; +Input::~Input() { } -void Input::setDiagHandler(SourceMgr::DiagHandlerTy Handler, void *Ctxt) { - SrcMgr.setDiagHandler(Handler, Ctxt); -} +std::error_code Input::error() { return EC; } + +// Pin the vtables to this file. +void Input::HNode::anchor() {} +void Input::EmptyHNode::anchor() {} +void Input::ScalarHNode::anchor() {} +void Input::MapHNode::anchor() {} +void Input::SequenceHNode::anchor() {} bool Input::outputting() { return false; @@ -60,25 +75,47 @@ bool Input::outputting() { bool Input::setCurrentDocument() { if (DocIterator != Strm->end()) { Node *N = DocIterator->getRoot(); + if (!N) { + assert(Strm->failed() && "Root is NULL iff parsing failed"); + EC = make_error_code(errc::invalid_argument); + return false; + } + if (isa(N)) { // Empty files are allowed and ignored ++DocIterator; return setCurrentDocument(); } - CurrentNode = this->createHNodes(N); + TopNode = this->createHNodes(N); + CurrentNode = TopNode.get(); return true; } return false; } -void Input::nextDocument() { - ++DocIterator; +bool Input::nextDocument() { + return ++DocIterator != Strm->end(); +} + +const Node *Input::getCurrentNode() const { + return CurrentNode ? CurrentNode->_node : nullptr; +} + +bool Input::mapTag(StringRef Tag, bool Default) { + std::string foundTag = CurrentNode->_node->getVerbatimTag(); + if (foundTag.empty()) { + // If no tag found and 'Tag' is the default, say it was found. + return Default; + } + // Return true iff found tag matches supplied tag. + return Tag.equals(foundTag); } void Input::beginMapping() { if (EC) return; - MapHNode *MN = dyn_cast(CurrentNode); + // CurrentNode can be null if the document is empty. + MapHNode *MN = dyn_cast_or_null(CurrentNode); if (MN) { MN->ValidKeys.clear(); } @@ -89,13 +126,22 @@ bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault, UseDefault = false; if (EC) return false; + + // CurrentNode is null for empty documents, which is an error in case required + // nodes are present. + if (!CurrentNode) { + if (Required) + EC = make_error_code(errc::invalid_argument); + return false; + } + MapHNode *MN = dyn_cast(CurrentNode); if (!MN) { setError(CurrentNode, "not a mapping"); return false; } MN->ValidKeys.push_back(Key); - HNode *Value = MN->Mapping[Key]; + HNode *Value = MN->Mapping[Key].get(); if (!Value) { if (Required) setError(CurrentNode, Twine("missing required key '") + Key + "'"); @@ -115,22 +161,34 @@ void Input::postflightKey(void *saveInfo) { void Input::endMapping() { if (EC) return; - MapHNode *MN = dyn_cast(CurrentNode); + // CurrentNode can be null if the document is empty. + MapHNode *MN = dyn_cast_or_null(CurrentNode); if (!MN) return; - for (MapHNode::NameToNode::iterator i = MN->Mapping.begin(), - End = MN->Mapping.end(); i != End; ++i) { - if (!MN->isValidKey(i->first)) { - setError(i->second, Twine("unknown key '") + i->first + "'"); + for (const auto &NN : MN->Mapping) { + if (!MN->isValidKey(NN.first())) { + setError(NN.second.get(), Twine("unknown key '") + NN.first() + "'"); break; } } } +void Input::beginFlowMapping() { beginMapping(); } + +void Input::endFlowMapping() { endMapping(); } + unsigned Input::beginSequence() { - if (SequenceHNode *SQ = dyn_cast(CurrentNode)) { + if (SequenceHNode *SQ = dyn_cast(CurrentNode)) return SQ->Entries.size(); + if (isa(CurrentNode)) + return 0; + // Treat case where there's a scalar "null" value as an empty sequence. + if (ScalarHNode *SN = dyn_cast(CurrentNode)) { + if (isNull(SN->value())) + return 0; } + // Any other type of HNode is an error. + setError(CurrentNode, "not a sequence"); return 0; } @@ -142,7 +200,7 @@ bool Input::preflightElement(unsigned Index, void *&SaveInfo) { return false; if (SequenceHNode *SQ = dyn_cast(CurrentNode)) { SaveInfo = CurrentNode; - CurrentNode = SQ->Entries[Index]; + CurrentNode = SQ->Entries[Index].get(); return true; } return false; @@ -152,19 +210,14 @@ void Input::postflightElement(void *SaveInfo) { CurrentNode = reinterpret_cast(SaveInfo); } -unsigned Input::beginFlowSequence() { - if (SequenceHNode *SQ = dyn_cast(CurrentNode)) { - return SQ->Entries.size(); - } - return 0; -} +unsigned Input::beginFlowSequence() { return beginSequence(); } bool Input::preflightFlowElement(unsigned index, void *&SaveInfo) { if (EC) return false; if (SequenceHNode *SQ = dyn_cast(CurrentNode)) { SaveInfo = CurrentNode; - CurrentNode = SQ->Entries[index]; + CurrentNode = SQ->Entries[index].get(); return true; } return false; @@ -193,6 +246,13 @@ bool Input::matchEnumScalar(const char *Str, bool) { return false; } +bool Input::matchEnumFallback() { + if (ScalarMatchFound) + return false; + ScalarMatchFound = true; + return true; +} + void Input::endEnumScalar() { if (!ScalarMatchFound) { setError(CurrentNode, "unknown enumerated scalar"); @@ -215,9 +275,8 @@ bool Input::bitSetMatch(const char *Str, bool) { return false; if (SequenceHNode *SQ = dyn_cast(CurrentNode)) { unsigned Index = 0; - for (std::vector::iterator i = SQ->Entries.begin(), - End = SQ->Entries.end(); i != End; ++i) { - if (ScalarHNode *SN = dyn_cast(*i)) { + for (auto &N : SQ->Entries) { + if (ScalarHNode *SN = dyn_cast(N.get())) { if (SN->value().equals(Str)) { BitValuesUsed[Index] = true; return true; @@ -240,14 +299,14 @@ void Input::endBitSetScalar() { assert(BitValuesUsed.size() == SQ->Entries.size()); for (unsigned i = 0; i < SQ->Entries.size(); ++i) { if (!BitValuesUsed[i]) { - setError(SQ->Entries[i], "unknown bit value"); + setError(SQ->Entries[i].get(), "unknown bit value"); return; } } } } -void Input::scalarString(StringRef &S) { +void Input::scalarString(StringRef &S, bool) { if (ScalarHNode *SN = dyn_cast(CurrentNode)) { S = SN->value(); } else { @@ -255,7 +314,10 @@ void Input::scalarString(StringRef &S) { } } +void Input::blockScalarString(StringRef &S) { scalarString(S, false); } + void Input::setError(HNode *hnode, const Twine &message) { + assert(hnode && "HNode must not be NULL"); this->setError(hnode->_node, message); } @@ -264,60 +326,59 @@ void Input::setError(Node *node, const Twine &message) { EC = make_error_code(errc::invalid_argument); } -Input::HNode *Input::createHNodes(Node *N) { +std::unique_ptr Input::createHNodes(Node *N) { SmallString<128> StringStorage; if (ScalarNode *SN = dyn_cast(N)) { StringRef KeyStr = SN->getValue(StringStorage); if (!StringStorage.empty()) { // Copy string to permanent storage - unsigned Len = StringStorage.size(); - char *Buf = Allocator.Allocate(Len); - memcpy(Buf, &StringStorage[0], Len); - KeyStr = StringRef(Buf, Len); + KeyStr = StringStorage.str().copy(StringAllocator); } - return new (Allocator) ScalarHNode(N, KeyStr); + return llvm::make_unique(N, KeyStr); + } else if (BlockScalarNode *BSN = dyn_cast(N)) { + StringRef ValueCopy = BSN->getValue().copy(StringAllocator); + return llvm::make_unique(N, ValueCopy); } else if (SequenceNode *SQ = dyn_cast(N)) { - SequenceHNode *SQHNode = new (Allocator) SequenceHNode(N); - for (SequenceNode::iterator i = SQ->begin(), End = SQ->end(); i != End; - ++i) { - HNode *Entry = this->createHNodes(i); + auto SQHNode = llvm::make_unique(N); + for (Node &SN : *SQ) { + auto Entry = this->createHNodes(&SN); if (EC) break; - SQHNode->Entries.push_back(Entry); + SQHNode->Entries.push_back(std::move(Entry)); } - return SQHNode; + return std::move(SQHNode); } else if (MappingNode *Map = dyn_cast(N)) { - MapHNode *mapHNode = new (Allocator) MapHNode(N); - for (MappingNode::iterator i = Map->begin(), End = Map->end(); i != End; - ++i) { - ScalarNode *KeyScalar = dyn_cast(i->getKey()); + auto mapHNode = llvm::make_unique(N); + for (KeyValueNode &KVN : *Map) { + Node *KeyNode = KVN.getKey(); + ScalarNode *KeyScalar = dyn_cast(KeyNode); + if (!KeyScalar) { + setError(KeyNode, "Map key must be a scalar"); + break; + } StringStorage.clear(); StringRef KeyStr = KeyScalar->getValue(StringStorage); if (!StringStorage.empty()) { // Copy string to permanent storage - unsigned Len = StringStorage.size(); - char *Buf = Allocator.Allocate(Len); - memcpy(Buf, &StringStorage[0], Len); - KeyStr = StringRef(Buf, Len); + KeyStr = StringStorage.str().copy(StringAllocator); } - HNode *ValueHNode = this->createHNodes(i->getValue()); + auto ValueHNode = this->createHNodes(KVN.getValue()); if (EC) break; - mapHNode->Mapping[KeyStr] = ValueHNode; + mapHNode->Mapping[KeyStr] = std::move(ValueHNode); } - return mapHNode; + return std::move(mapHNode); } else if (isa(N)) { - return new (Allocator) EmptyHNode(N); + return llvm::make_unique(N); } else { setError(N, "unknown node kind"); - return NULL; + return nullptr; } } bool Input::MapHNode::isValidKey(StringRef Key) { - for (SmallVector::iterator i = ValidKeys.begin(), - End = ValidKeys.end(); i != End; ++i) { - if (Key.equals(*i)) + for (const char *K : ValidKeys) { + if (Key.equals(K)) return true; } return false; @@ -327,15 +388,21 @@ void Input::setError(const Twine &Message) { this->setError(CurrentNode, Message); } +bool Input::canElideEmptySequence() { + return false; +} + //===----------------------------------------------------------------------===// // Output //===----------------------------------------------------------------------===// -Output::Output(raw_ostream &yout, void *context) +Output::Output(raw_ostream &yout, void *context, int WrapColumn) : IO(context), Out(yout), + WrapColumn(WrapColumn), Column(0), ColumnAtFlowStart(0), + ColumnAtMapFlowStart(0), NeedBitValueComma(false), NeedFlowSequenceComma(false), EnumerationMatchFound(false), @@ -354,6 +421,14 @@ void Output::beginMapping() { NeedsNewLine = true; } +bool Output::mapTag(StringRef Tag, bool Use) { + if (Use) { + this->output(" "); + this->output(Tag); + } + return Use; +} + void Output::endMapping() { StateStack.pop_back(); } @@ -362,8 +437,13 @@ bool Output::preflightKey(const char *Key, bool Required, bool SameAsDefault, bool &UseDefault, void *&) { UseDefault = false; if (Required || !SameAsDefault) { - this->newLineCheck(); - this->paddedKey(Key); + auto State = StateStack.back(); + if (State == inFlowMapFirstKey || State == inFlowMapOtherKey) { + flowKey(Key); + } else { + this->newLineCheck(); + this->paddedKey(Key); + } return true; } return false; @@ -373,9 +453,24 @@ void Output::postflightKey(void *) { if (StateStack.back() == inMapFirstKey) { StateStack.pop_back(); StateStack.push_back(inMapOtherKey); + } else if (StateStack.back() == inFlowMapFirstKey) { + StateStack.pop_back(); + StateStack.push_back(inFlowMapOtherKey); } } +void Output::beginFlowMapping() { + StateStack.push_back(inFlowMapFirstKey); + this->newLineCheck(); + ColumnAtMapFlowStart = Column; + output("{ "); +} + +void Output::endFlowMapping() { + StateStack.pop_back(); + this->outputUpToEndOfLine(" }"); +} + void Output::beginDocuments() { this->outputUpToEndOfLine("---"); } @@ -411,8 +506,8 @@ void Output::postflightElement(void *) { } unsigned Output::beginFlowSequence() { - this->newLineCheck(); StateStack.push_back(inFlowSeq); + this->newLineCheck(); ColumnAtFlowStart = Column; output("[ "); NeedFlowSequenceComma = false; @@ -427,7 +522,7 @@ void Output::endFlowSequence() { bool Output::preflightFlowElement(unsigned, void *&) { if (NeedFlowSequenceComma) output(", "); - if (Column > 70) { + if (WrapColumn && Column > WrapColumn) { output("\n"); for (int i = 0; i < ColumnAtFlowStart; ++i) output(" "); @@ -454,6 +549,13 @@ bool Output::matchEnumScalar(const char *Str, bool Match) { return false; } +bool Output::matchEnumFallback() { + if (EnumerationMatchFound) + return false; + EnumerationMatchFound = true; + return true; +} + void Output::endEnumScalar() { if (!EnumerationMatchFound) llvm_unreachable("bad runtime enum value"); @@ -481,10 +583,16 @@ void Output::endBitSetScalar() { this->outputUpToEndOfLine(" ]"); } -void Output::scalarString(StringRef &S) { +void Output::scalarString(StringRef &S, bool MustQuote) { this->newLineCheck(); - if (S.find('\n') == StringRef::npos) { - // No embedded new-line chars, just print string. + if (S.empty()) { + // Print '' for the empty string because leaving the field empty is not + // allowed. + this->outputUpToEndOfLine("''"); + return; + } + if (!MustQuote) { + // Only quote if we must. this->outputUpToEndOfLine(S); return; } @@ -506,9 +614,40 @@ void Output::scalarString(StringRef &S) { this->outputUpToEndOfLine("'"); // Ending single quote. } +void Output::blockScalarString(StringRef &S) { + if (!StateStack.empty()) + newLineCheck(); + output(" |"); + outputNewLine(); + + unsigned Indent = StateStack.empty() ? 1 : StateStack.size(); + + auto Buffer = MemoryBuffer::getMemBuffer(S, "", false); + for (line_iterator Lines(*Buffer, false); !Lines.is_at_end(); ++Lines) { + for (unsigned I = 0; I < Indent; ++I) { + output(" "); + } + output(*Lines); + outputNewLine(); + } +} + void Output::setError(const Twine &message) { } +bool Output::canElideEmptySequence() { + // Normally, with an optional key/value where the value is an empty sequence, + // the whole key/value can be not written. But, that produces wrong yaml + // if the key/value is the only thing in the map and the map is used in + // a sequence. This detects if the this sequence is the first key/value + // in map that itself is embedded in a sequnce. + if (StateStack.size() < 2) + return true; + if (StateStack.back() != inMapFirstKey) + return true; + return (StateStack[StateStack.size()-2] != inSeq); +} + void Output::output(StringRef s) { Column += s.size(); Out << s; @@ -516,7 +655,9 @@ void Output::output(StringRef s) { void Output::outputUpToEndOfLine(StringRef s) { this->output(s); - if (StateStack.empty() || StateStack.back() != inFlowSeq) + if (StateStack.empty() || (StateStack.back() != inFlowSeq && + StateStack.back() != inFlowMapFirstKey && + StateStack.back() != inFlowMapOtherKey)) NeedsNewLine = true; } @@ -542,7 +683,9 @@ void Output::newLineCheck() { if (StateStack.back() == inSeq) { OutputDash = true; - } else if ((StateStack.size() > 1) && (StateStack.back() == inMapFirstKey) && + } else if ((StateStack.size() > 1) && ((StateStack.back() == inMapFirstKey) || + (StateStack.back() == inFlowSeq) || + (StateStack.back() == inFlowMapFirstKey)) && (StateStack[StateStack.size() - 2] == inSeq)) { --Indent; OutputDash = true; @@ -567,6 +710,20 @@ void Output::paddedKey(StringRef key) { output(" "); } +void Output::flowKey(StringRef Key) { + if (StateStack.back() == inFlowMapOtherKey) + output(", "); + if (WrapColumn && Column > WrapColumn) { + output("\n"); + for (int I = 0; I < ColumnAtMapFlowStart; ++I) + output(" "); + Column = ColumnAtMapFlowStart; + output(" "); + } + output(Key); + output(": "); +} + //===----------------------------------------------------------------------===// // traits for built-in types //===----------------------------------------------------------------------===// @@ -597,6 +754,17 @@ StringRef ScalarTraits::input(StringRef Scalar, void *, return StringRef(); } +void ScalarTraits::output(const std::string &Val, void *, + raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits::input(StringRef Scalar, void *, + std::string &Val) { + Val = Scalar.str(); + return StringRef(); +} + void ScalarTraits::output(const uint8_t &Val, void *, raw_ostream &Out) { // use temp uin32_t because ostream thinks uint8_t is a character