xref: /freebsd/contrib/llvm-project/llvm/lib/BinaryFormat/MsgPackDocumentYAML.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
10b57cec5SDimitry Andric //===-- MsgPackDocumentYAML.cpp - MsgPack Document YAML interface -------*-===//
20b57cec5SDimitry Andric //
3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// This file implements YAMLIO on a msgpack::Document.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/BinaryFormat/MsgPackDocument.h"
140b57cec5SDimitry Andric #include "llvm/Support/YAMLTraits.h"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric using namespace llvm;
170b57cec5SDimitry Andric using namespace msgpack;
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace {
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric // Struct used to represent scalar node. (MapDocNode and ArrayDocNode already
220b57cec5SDimitry Andric // exist in MsgPackDocument.h.)
230b57cec5SDimitry Andric struct ScalarDocNode : DocNode {
ScalarDocNode__anonbd77ee450111::ScalarDocNode240b57cec5SDimitry Andric   ScalarDocNode(DocNode N) : DocNode(N) {}
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric   /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
270b57cec5SDimitry Andric   /// returns something else if the result of toString would be ambiguous, e.g.
280b57cec5SDimitry Andric   /// a string that parses as a number or boolean.
290b57cec5SDimitry Andric   StringRef getYAMLTag() const;
300b57cec5SDimitry Andric };
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric } // namespace
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric /// Convert this DocNode to a string, assuming it is scalar.
toString() const350b57cec5SDimitry Andric std::string DocNode::toString() const {
360b57cec5SDimitry Andric   std::string S;
370b57cec5SDimitry Andric   raw_string_ostream OS(S);
380b57cec5SDimitry Andric   switch (getKind()) {
390b57cec5SDimitry Andric   case msgpack::Type::String:
400b57cec5SDimitry Andric     OS << Raw;
410b57cec5SDimitry Andric     break;
420b57cec5SDimitry Andric   case msgpack::Type::Nil:
430b57cec5SDimitry Andric     break;
440b57cec5SDimitry Andric   case msgpack::Type::Boolean:
450b57cec5SDimitry Andric     OS << (Bool ? "true" : "false");
460b57cec5SDimitry Andric     break;
470b57cec5SDimitry Andric   case msgpack::Type::Int:
480b57cec5SDimitry Andric     OS << Int;
490b57cec5SDimitry Andric     break;
500b57cec5SDimitry Andric   case msgpack::Type::UInt:
510b57cec5SDimitry Andric     if (getDocument()->getHexMode())
520b57cec5SDimitry Andric       OS << format("%#llx", (unsigned long long)UInt);
530b57cec5SDimitry Andric     else
540b57cec5SDimitry Andric       OS << UInt;
550b57cec5SDimitry Andric     break;
560b57cec5SDimitry Andric   case msgpack::Type::Float:
570b57cec5SDimitry Andric     OS << Float;
580b57cec5SDimitry Andric     break;
590b57cec5SDimitry Andric   default:
600b57cec5SDimitry Andric     llvm_unreachable("not scalar");
610b57cec5SDimitry Andric     break;
620b57cec5SDimitry Andric   }
630b57cec5SDimitry Andric   return OS.str();
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric /// Convert the StringRef and use it to set this DocNode (assuming scalar). If
670b57cec5SDimitry Andric /// it is a string, copy the string into the Document's strings list so we do
680b57cec5SDimitry Andric /// not rely on S having a lifetime beyond this call. Tag is "" or a YAML tag.
fromString(StringRef S,StringRef Tag)690b57cec5SDimitry Andric StringRef DocNode::fromString(StringRef S, StringRef Tag) {
700b57cec5SDimitry Andric   if (Tag == "tag:yaml.org,2002:str")
710b57cec5SDimitry Andric     Tag = "";
720b57cec5SDimitry Andric   if (Tag == "!int" || Tag == "") {
730b57cec5SDimitry Andric     // Try unsigned int then signed int.
740b57cec5SDimitry Andric     *this = getDocument()->getNode(uint64_t(0));
750b57cec5SDimitry Andric     StringRef Err = yaml::ScalarTraits<uint64_t>::input(S, nullptr, getUInt());
760b57cec5SDimitry Andric     if (Err != "") {
770b57cec5SDimitry Andric       *this = getDocument()->getNode(int64_t(0));
780b57cec5SDimitry Andric       Err = yaml::ScalarTraits<int64_t>::input(S, nullptr, getInt());
790b57cec5SDimitry Andric     }
800b57cec5SDimitry Andric     if (Err == "" || Tag != "")
810b57cec5SDimitry Andric       return Err;
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric   if (Tag == "!nil") {
840b57cec5SDimitry Andric     *this = getDocument()->getNode();
850b57cec5SDimitry Andric     return "";
860b57cec5SDimitry Andric   }
870b57cec5SDimitry Andric   if (Tag == "!bool" || Tag == "") {
880b57cec5SDimitry Andric     *this = getDocument()->getNode(false);
890b57cec5SDimitry Andric     StringRef Err = yaml::ScalarTraits<bool>::input(S, nullptr, getBool());
900b57cec5SDimitry Andric     if (Err == "" || Tag != "")
910b57cec5SDimitry Andric       return Err;
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric   if (Tag == "!float" || Tag == "") {
940b57cec5SDimitry Andric     *this = getDocument()->getNode(0.0);
950b57cec5SDimitry Andric     StringRef Err = yaml::ScalarTraits<double>::input(S, nullptr, getFloat());
960b57cec5SDimitry Andric     if (Err == "" || Tag != "")
970b57cec5SDimitry Andric       return Err;
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric   assert((Tag == "!str" || Tag == "") && "unsupported tag");
1000b57cec5SDimitry Andric   std::string V;
1010b57cec5SDimitry Andric   StringRef Err = yaml::ScalarTraits<std::string>::input(S, nullptr, V);
1020b57cec5SDimitry Andric   if (Err == "")
1030b57cec5SDimitry Andric     *this = getDocument()->getNode(V, /*Copy=*/true);
1040b57cec5SDimitry Andric   return Err;
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
1080b57cec5SDimitry Andric /// returns something else if the result of toString would be ambiguous, e.g.
1090b57cec5SDimitry Andric /// a string that parses as a number or boolean.
getYAMLTag() const1100b57cec5SDimitry Andric StringRef ScalarDocNode::getYAMLTag() const {
1110b57cec5SDimitry Andric   if (getKind() == msgpack::Type::Nil)
1120b57cec5SDimitry Andric     return "!nil";
1130b57cec5SDimitry Andric   // Try converting both ways and see if we get the same kind. If not, we need
1140b57cec5SDimitry Andric   // a tag.
1150b57cec5SDimitry Andric   ScalarDocNode N = getDocument()->getNode();
1160b57cec5SDimitry Andric   N.fromString(toString(), "");
1170b57cec5SDimitry Andric   if (N.getKind() == getKind())
1180b57cec5SDimitry Andric     return "";
1190b57cec5SDimitry Andric   // Tolerate signedness of int changing, as tags do not differentiate between
1200b57cec5SDimitry Andric   // them anyway.
1210b57cec5SDimitry Andric   if (N.getKind() == msgpack::Type::UInt && getKind() == msgpack::Type::Int)
1220b57cec5SDimitry Andric     return "";
1230b57cec5SDimitry Andric   if (N.getKind() == msgpack::Type::Int && getKind() == msgpack::Type::UInt)
1240b57cec5SDimitry Andric     return "";
1250b57cec5SDimitry Andric   // We do need a tag.
1260b57cec5SDimitry Andric   switch (getKind()) {
1270b57cec5SDimitry Andric   case msgpack::Type::String:
1280b57cec5SDimitry Andric     return "!str";
1290b57cec5SDimitry Andric   case msgpack::Type::Int:
1300b57cec5SDimitry Andric     return "!int";
1310b57cec5SDimitry Andric   case msgpack::Type::UInt:
1320b57cec5SDimitry Andric     return "!int";
1330b57cec5SDimitry Andric   case msgpack::Type::Boolean:
1340b57cec5SDimitry Andric     return "!bool";
1350b57cec5SDimitry Andric   case msgpack::Type::Float:
1360b57cec5SDimitry Andric     return "!float";
1370b57cec5SDimitry Andric   default:
1380b57cec5SDimitry Andric     llvm_unreachable("unrecognized kind");
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric namespace llvm {
1430b57cec5SDimitry Andric namespace yaml {
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric /// YAMLIO for DocNode
1460b57cec5SDimitry Andric template <> struct PolymorphicTraits<DocNode> {
1470b57cec5SDimitry Andric 
getKindllvm::yaml::PolymorphicTraits1480b57cec5SDimitry Andric   static NodeKind getKind(const DocNode &N) {
1490b57cec5SDimitry Andric     switch (N.getKind()) {
1500b57cec5SDimitry Andric     case msgpack::Type::Map:
1510b57cec5SDimitry Andric       return NodeKind::Map;
1520b57cec5SDimitry Andric     case msgpack::Type::Array:
1530b57cec5SDimitry Andric       return NodeKind::Sequence;
1540b57cec5SDimitry Andric     default:
1550b57cec5SDimitry Andric       return NodeKind::Scalar;
1560b57cec5SDimitry Andric     }
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric 
getAsMapllvm::yaml::PolymorphicTraits1590b57cec5SDimitry Andric   static MapDocNode &getAsMap(DocNode &N) { return N.getMap(/*Convert=*/true); }
1600b57cec5SDimitry Andric 
getAsSequencellvm::yaml::PolymorphicTraits1610b57cec5SDimitry Andric   static ArrayDocNode &getAsSequence(DocNode &N) {
1620b57cec5SDimitry Andric     N.getArray(/*Convert=*/true);
1630b57cec5SDimitry Andric     return *static_cast<ArrayDocNode *>(&N);
1640b57cec5SDimitry Andric   }
1650b57cec5SDimitry Andric 
getAsScalarllvm::yaml::PolymorphicTraits1660b57cec5SDimitry Andric   static ScalarDocNode &getAsScalar(DocNode &N) {
1670b57cec5SDimitry Andric     return *static_cast<ScalarDocNode *>(&N);
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric };
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric /// YAMLIO for ScalarDocNode
1720b57cec5SDimitry Andric template <> struct TaggedScalarTraits<ScalarDocNode> {
1730b57cec5SDimitry Andric 
outputllvm::yaml::TaggedScalarTraits1740b57cec5SDimitry Andric   static void output(const ScalarDocNode &S, void *Ctxt, raw_ostream &OS,
1750b57cec5SDimitry Andric                      raw_ostream &TagOS) {
1760b57cec5SDimitry Andric     TagOS << S.getYAMLTag();
1770b57cec5SDimitry Andric     OS << S.toString();
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric 
inputllvm::yaml::TaggedScalarTraits1800b57cec5SDimitry Andric   static StringRef input(StringRef Str, StringRef Tag, void *Ctxt,
1810b57cec5SDimitry Andric                          ScalarDocNode &S) {
1820b57cec5SDimitry Andric     return S.fromString(Str, Tag);
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
mustQuotellvm::yaml::TaggedScalarTraits1850b57cec5SDimitry Andric   static QuotingType mustQuote(const ScalarDocNode &S, StringRef ScalarStr) {
1860b57cec5SDimitry Andric     switch (S.getKind()) {
1870b57cec5SDimitry Andric     case Type::Int:
1880b57cec5SDimitry Andric       return ScalarTraits<int64_t>::mustQuote(ScalarStr);
1890b57cec5SDimitry Andric     case Type::UInt:
1900b57cec5SDimitry Andric       return ScalarTraits<uint64_t>::mustQuote(ScalarStr);
1910b57cec5SDimitry Andric     case Type::Nil:
1920b57cec5SDimitry Andric       return ScalarTraits<StringRef>::mustQuote(ScalarStr);
1930b57cec5SDimitry Andric     case Type::Boolean:
1940b57cec5SDimitry Andric       return ScalarTraits<bool>::mustQuote(ScalarStr);
1950b57cec5SDimitry Andric     case Type::Float:
1960b57cec5SDimitry Andric       return ScalarTraits<double>::mustQuote(ScalarStr);
1970b57cec5SDimitry Andric     case Type::Binary:
1980b57cec5SDimitry Andric     case Type::String:
1990b57cec5SDimitry Andric       return ScalarTraits<std::string>::mustQuote(ScalarStr);
2000b57cec5SDimitry Andric     default:
2010b57cec5SDimitry Andric       llvm_unreachable("unrecognized ScalarKind");
2020b57cec5SDimitry Andric     }
2030b57cec5SDimitry Andric   }
2040b57cec5SDimitry Andric };
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric /// YAMLIO for MapDocNode
2070b57cec5SDimitry Andric template <> struct CustomMappingTraits<MapDocNode> {
2080b57cec5SDimitry Andric 
inputOnellvm::yaml::CustomMappingTraits2090b57cec5SDimitry Andric   static void inputOne(IO &IO, StringRef Key, MapDocNode &M) {
2100b57cec5SDimitry Andric     ScalarDocNode KeyObj = M.getDocument()->getNode();
2110b57cec5SDimitry Andric     KeyObj.fromString(Key, "");
2120b57cec5SDimitry Andric     IO.mapRequired(Key.str().c_str(), M.getMap()[KeyObj]);
2130b57cec5SDimitry Andric   }
2140b57cec5SDimitry Andric 
outputllvm::yaml::CustomMappingTraits2150b57cec5SDimitry Andric   static void output(IO &IO, MapDocNode &M) {
2160b57cec5SDimitry Andric     for (auto I : M.getMap()) {
2170b57cec5SDimitry Andric       IO.mapRequired(I.first.toString().c_str(), I.second);
2180b57cec5SDimitry Andric     }
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric };
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric /// YAMLIO for ArrayNode
2230b57cec5SDimitry Andric template <> struct SequenceTraits<ArrayDocNode> {
2240b57cec5SDimitry Andric 
sizellvm::yaml::SequenceTraits2250b57cec5SDimitry Andric   static size_t size(IO &IO, ArrayDocNode &A) { return A.size(); }
2260b57cec5SDimitry Andric 
elementllvm::yaml::SequenceTraits2270b57cec5SDimitry Andric   static DocNode &element(IO &IO, ArrayDocNode &A, size_t Index) {
2280b57cec5SDimitry Andric     return A[Index];
2290b57cec5SDimitry Andric   }
2300b57cec5SDimitry Andric };
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric } // namespace yaml
2330b57cec5SDimitry Andric } // namespace llvm
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric /// Convert MsgPack Document to YAML text.
toYAML(raw_ostream & OS)2360b57cec5SDimitry Andric void msgpack::Document::toYAML(raw_ostream &OS) {
2370b57cec5SDimitry Andric   yaml::Output Yout(OS);
2380b57cec5SDimitry Andric   Yout << getRoot();
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric /// Read YAML text into the MsgPack document. Returns false on failure.
fromYAML(StringRef S)2420b57cec5SDimitry Andric bool msgpack::Document::fromYAML(StringRef S) {
2430b57cec5SDimitry Andric   clear();
2440b57cec5SDimitry Andric   yaml::Input Yin(S);
2450b57cec5SDimitry Andric   Yin >> getRoot();
2460b57cec5SDimitry Andric   return !Yin.error();
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric 
249