xref: /llvm-project/llvm/lib/BinaryFormat/MsgPackDocumentYAML.cpp (revision c874dd53628db8170d4c5ba3878817abc385a695)
14ced8de1STim Renouf //===-- MsgPackDocumentYAML.cpp - MsgPack Document YAML interface -------*-===//
24ced8de1STim Renouf //
3*c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
5*c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64ced8de1STim Renouf //
74ced8de1STim Renouf //===----------------------------------------------------------------------===//
84ced8de1STim Renouf //
94ced8de1STim Renouf /// This file implements YAMLIO on a msgpack::Document.
104ced8de1STim Renouf //
114ced8de1STim Renouf //===----------------------------------------------------------------------===//
124ced8de1STim Renouf 
134ced8de1STim Renouf #include "llvm/BinaryFormat/MsgPackDocument.h"
144ced8de1STim Renouf #include "llvm/Support/YAMLTraits.h"
154ced8de1STim Renouf 
164ced8de1STim Renouf using namespace llvm;
174ced8de1STim Renouf using namespace msgpack;
184ced8de1STim Renouf 
194ced8de1STim Renouf namespace {
204ced8de1STim Renouf 
214ced8de1STim Renouf // Struct used to represent scalar node. (MapDocNode and ArrayDocNode already
224ced8de1STim Renouf // exist in MsgPackDocument.h.)
234ced8de1STim Renouf struct ScalarDocNode : DocNode {
ScalarDocNode__anond02472780111::ScalarDocNode244ced8de1STim Renouf   ScalarDocNode(DocNode N) : DocNode(N) {}
254ced8de1STim Renouf 
264ced8de1STim Renouf   /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
274ced8de1STim Renouf   /// returns something else if the result of toString would be ambiguous, e.g.
284ced8de1STim Renouf   /// a string that parses as a number or boolean.
294ced8de1STim Renouf   StringRef getYAMLTag() const;
304ced8de1STim Renouf };
314ced8de1STim Renouf 
324ced8de1STim Renouf } // namespace
334ced8de1STim Renouf 
344ced8de1STim Renouf /// Convert this DocNode to a string, assuming it is scalar.
toString() const354ced8de1STim Renouf std::string DocNode::toString() const {
364ced8de1STim Renouf   std::string S;
374ced8de1STim Renouf   raw_string_ostream OS(S);
384ced8de1STim Renouf   switch (getKind()) {
394ced8de1STim Renouf   case msgpack::Type::String:
404ced8de1STim Renouf     OS << Raw;
414ced8de1STim Renouf     break;
424ced8de1STim Renouf   case msgpack::Type::Nil:
434ced8de1STim Renouf     break;
444ced8de1STim Renouf   case msgpack::Type::Boolean:
454ced8de1STim Renouf     OS << (Bool ? "true" : "false");
464ced8de1STim Renouf     break;
474ced8de1STim Renouf   case msgpack::Type::Int:
484ced8de1STim Renouf     OS << Int;
494ced8de1STim Renouf     break;
504ced8de1STim Renouf   case msgpack::Type::UInt:
514ced8de1STim Renouf     if (getDocument()->getHexMode())
524ced8de1STim Renouf       OS << format("%#llx", (unsigned long long)UInt);
534ced8de1STim Renouf     else
544ced8de1STim Renouf       OS << UInt;
554ced8de1STim Renouf     break;
564ced8de1STim Renouf   case msgpack::Type::Float:
574ced8de1STim Renouf     OS << Float;
584ced8de1STim Renouf     break;
594ced8de1STim Renouf   default:
604ced8de1STim Renouf     llvm_unreachable("not scalar");
614ced8de1STim Renouf     break;
624ced8de1STim Renouf   }
638723a565STim Renouf   return OS.str();
644ced8de1STim Renouf }
654ced8de1STim Renouf 
664ced8de1STim Renouf /// Convert the StringRef and use it to set this DocNode (assuming scalar). If
674ced8de1STim Renouf /// it is a string, copy the string into the Document's strings list so we do
684ced8de1STim Renouf /// not rely on S having a lifetime beyond this call. Tag is "" or a YAML tag.
fromString(StringRef S,StringRef Tag)694ced8de1STim Renouf StringRef DocNode::fromString(StringRef S, StringRef Tag) {
704ced8de1STim Renouf   if (Tag == "tag:yaml.org,2002:str")
714ced8de1STim Renouf     Tag = "";
724ced8de1STim Renouf   if (Tag == "!int" || Tag == "") {
734ced8de1STim Renouf     // Try unsigned int then signed int.
744ced8de1STim Renouf     *this = getDocument()->getNode(uint64_t(0));
754ced8de1STim Renouf     StringRef Err = yaml::ScalarTraits<uint64_t>::input(S, nullptr, getUInt());
764ced8de1STim Renouf     if (Err != "") {
774ced8de1STim Renouf       *this = getDocument()->getNode(int64_t(0));
784ced8de1STim Renouf       Err = yaml::ScalarTraits<int64_t>::input(S, nullptr, getInt());
794ced8de1STim Renouf     }
804ced8de1STim Renouf     if (Err == "" || Tag != "")
814ced8de1STim Renouf       return Err;
824ced8de1STim Renouf   }
834ced8de1STim Renouf   if (Tag == "!nil") {
844ced8de1STim Renouf     *this = getDocument()->getNode();
854ced8de1STim Renouf     return "";
864ced8de1STim Renouf   }
874ced8de1STim Renouf   if (Tag == "!bool" || Tag == "") {
884ced8de1STim Renouf     *this = getDocument()->getNode(false);
894ced8de1STim Renouf     StringRef Err = yaml::ScalarTraits<bool>::input(S, nullptr, getBool());
904ced8de1STim Renouf     if (Err == "" || Tag != "")
914ced8de1STim Renouf       return Err;
924ced8de1STim Renouf   }
934ced8de1STim Renouf   if (Tag == "!float" || Tag == "") {
944ced8de1STim Renouf     *this = getDocument()->getNode(0.0);
954ced8de1STim Renouf     StringRef Err = yaml::ScalarTraits<double>::input(S, nullptr, getFloat());
964ced8de1STim Renouf     if (Err == "" || Tag != "")
974ced8de1STim Renouf       return Err;
984ced8de1STim Renouf   }
994ced8de1STim Renouf   assert((Tag == "!str" || Tag == "") && "unsupported tag");
1004ced8de1STim Renouf   std::string V;
1014ced8de1STim Renouf   StringRef Err = yaml::ScalarTraits<std::string>::input(S, nullptr, V);
1024ced8de1STim Renouf   if (Err == "")
1034ced8de1STim Renouf     *this = getDocument()->getNode(V, /*Copy=*/true);
1044ced8de1STim Renouf   return Err;
1054ced8de1STim Renouf }
1064ced8de1STim Renouf 
1074ced8de1STim Renouf /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
1084ced8de1STim Renouf /// returns something else if the result of toString would be ambiguous, e.g.
1094ced8de1STim Renouf /// a string that parses as a number or boolean.
getYAMLTag() const1104ced8de1STim Renouf StringRef ScalarDocNode::getYAMLTag() const {
1114ced8de1STim Renouf   if (getKind() == msgpack::Type::Nil)
1124ced8de1STim Renouf     return "!nil";
1134ced8de1STim Renouf   // Try converting both ways and see if we get the same kind. If not, we need
1144ced8de1STim Renouf   // a tag.
1154ced8de1STim Renouf   ScalarDocNode N = getDocument()->getNode();
1164ced8de1STim Renouf   N.fromString(toString(), "");
1174ced8de1STim Renouf   if (N.getKind() == getKind())
1184ced8de1STim Renouf     return "";
1194ced8de1STim Renouf   // Tolerate signedness of int changing, as tags do not differentiate between
1204ced8de1STim Renouf   // them anyway.
1214ced8de1STim Renouf   if (N.getKind() == msgpack::Type::UInt && getKind() == msgpack::Type::Int)
1224ced8de1STim Renouf     return "";
1234ced8de1STim Renouf   if (N.getKind() == msgpack::Type::Int && getKind() == msgpack::Type::UInt)
1244ced8de1STim Renouf     return "";
1254ced8de1STim Renouf   // We do need a tag.
1264ced8de1STim Renouf   switch (getKind()) {
1274ced8de1STim Renouf   case msgpack::Type::String:
1284ced8de1STim Renouf     return "!str";
1294ced8de1STim Renouf   case msgpack::Type::Int:
1304ced8de1STim Renouf     return "!int";
1314ced8de1STim Renouf   case msgpack::Type::UInt:
1324ced8de1STim Renouf     return "!int";
1334ced8de1STim Renouf   case msgpack::Type::Boolean:
1344ced8de1STim Renouf     return "!bool";
1354ced8de1STim Renouf   case msgpack::Type::Float:
1364ced8de1STim Renouf     return "!float";
1374ced8de1STim Renouf   default:
1384ced8de1STim Renouf     llvm_unreachable("unrecognized kind");
1394ced8de1STim Renouf   }
1404ced8de1STim Renouf }
1414ced8de1STim Renouf 
1424ced8de1STim Renouf namespace llvm {
1434ced8de1STim Renouf namespace yaml {
1444ced8de1STim Renouf 
1454ced8de1STim Renouf /// YAMLIO for DocNode
1464ced8de1STim Renouf template <> struct PolymorphicTraits<DocNode> {
1474ced8de1STim Renouf 
getKindllvm::yaml::PolymorphicTraits1484ced8de1STim Renouf   static NodeKind getKind(const DocNode &N) {
1494ced8de1STim Renouf     switch (N.getKind()) {
1504ced8de1STim Renouf     case msgpack::Type::Map:
1514ced8de1STim Renouf       return NodeKind::Map;
1524ced8de1STim Renouf     case msgpack::Type::Array:
1534ced8de1STim Renouf       return NodeKind::Sequence;
1544ced8de1STim Renouf     default:
1554ced8de1STim Renouf       return NodeKind::Scalar;
1564ced8de1STim Renouf     }
1574ced8de1STim Renouf   }
1584ced8de1STim Renouf 
getAsMapllvm::yaml::PolymorphicTraits1594ced8de1STim Renouf   static MapDocNode &getAsMap(DocNode &N) { return N.getMap(/*Convert=*/true); }
1604ced8de1STim Renouf 
getAsSequencellvm::yaml::PolymorphicTraits1614ced8de1STim Renouf   static ArrayDocNode &getAsSequence(DocNode &N) {
1624ced8de1STim Renouf     N.getArray(/*Convert=*/true);
1634ced8de1STim Renouf     return *static_cast<ArrayDocNode *>(&N);
1644ced8de1STim Renouf   }
1654ced8de1STim Renouf 
getAsScalarllvm::yaml::PolymorphicTraits1664ced8de1STim Renouf   static ScalarDocNode &getAsScalar(DocNode &N) {
1674ced8de1STim Renouf     return *static_cast<ScalarDocNode *>(&N);
1684ced8de1STim Renouf   }
1694ced8de1STim Renouf };
1704ced8de1STim Renouf 
1714ced8de1STim Renouf /// YAMLIO for ScalarDocNode
1724ced8de1STim Renouf template <> struct TaggedScalarTraits<ScalarDocNode> {
1734ced8de1STim Renouf 
outputllvm::yaml::TaggedScalarTraits1744ced8de1STim Renouf   static void output(const ScalarDocNode &S, void *Ctxt, raw_ostream &OS,
1754ced8de1STim Renouf                      raw_ostream &TagOS) {
1764ced8de1STim Renouf     TagOS << S.getYAMLTag();
1774ced8de1STim Renouf     OS << S.toString();
1784ced8de1STim Renouf   }
1794ced8de1STim Renouf 
inputllvm::yaml::TaggedScalarTraits1804ced8de1STim Renouf   static StringRef input(StringRef Str, StringRef Tag, void *Ctxt,
1814ced8de1STim Renouf                          ScalarDocNode &S) {
1824ced8de1STim Renouf     return S.fromString(Str, Tag);
1834ced8de1STim Renouf   }
1844ced8de1STim Renouf 
mustQuotellvm::yaml::TaggedScalarTraits1854ced8de1STim Renouf   static QuotingType mustQuote(const ScalarDocNode &S, StringRef ScalarStr) {
1864ced8de1STim Renouf     switch (S.getKind()) {
1874ced8de1STim Renouf     case Type::Int:
1884ced8de1STim Renouf       return ScalarTraits<int64_t>::mustQuote(ScalarStr);
1894ced8de1STim Renouf     case Type::UInt:
1904ced8de1STim Renouf       return ScalarTraits<uint64_t>::mustQuote(ScalarStr);
1914ced8de1STim Renouf     case Type::Nil:
1924ced8de1STim Renouf       return ScalarTraits<StringRef>::mustQuote(ScalarStr);
1934ced8de1STim Renouf     case Type::Boolean:
1944ced8de1STim Renouf       return ScalarTraits<bool>::mustQuote(ScalarStr);
1954ced8de1STim Renouf     case Type::Float:
1964ced8de1STim Renouf       return ScalarTraits<double>::mustQuote(ScalarStr);
1974ced8de1STim Renouf     case Type::Binary:
1984ced8de1STim Renouf     case Type::String:
1994ced8de1STim Renouf       return ScalarTraits<std::string>::mustQuote(ScalarStr);
2004ced8de1STim Renouf     default:
2014ced8de1STim Renouf       llvm_unreachable("unrecognized ScalarKind");
2024ced8de1STim Renouf     }
2034ced8de1STim Renouf   }
2044ced8de1STim Renouf };
2054ced8de1STim Renouf 
2064ced8de1STim Renouf /// YAMLIO for MapDocNode
2074ced8de1STim Renouf template <> struct CustomMappingTraits<MapDocNode> {
2084ced8de1STim Renouf 
inputOnellvm::yaml::CustomMappingTraits2094ced8de1STim Renouf   static void inputOne(IO &IO, StringRef Key, MapDocNode &M) {
2104ced8de1STim Renouf     ScalarDocNode KeyObj = M.getDocument()->getNode();
2114ced8de1STim Renouf     KeyObj.fromString(Key, "");
2124ced8de1STim Renouf     IO.mapRequired(Key.str().c_str(), M.getMap()[KeyObj]);
2134ced8de1STim Renouf   }
2144ced8de1STim Renouf 
outputllvm::yaml::CustomMappingTraits2154ced8de1STim Renouf   static void output(IO &IO, MapDocNode &M) {
2164ced8de1STim Renouf     for (auto I : M.getMap()) {
2174ced8de1STim Renouf       IO.mapRequired(I.first.toString().c_str(), I.second);
2184ced8de1STim Renouf     }
2194ced8de1STim Renouf   }
2204ced8de1STim Renouf };
2214ced8de1STim Renouf 
2224ced8de1STim Renouf /// YAMLIO for ArrayNode
2234ced8de1STim Renouf template <> struct SequenceTraits<ArrayDocNode> {
2244ced8de1STim Renouf 
sizellvm::yaml::SequenceTraits2254ced8de1STim Renouf   static size_t size(IO &IO, ArrayDocNode &A) { return A.size(); }
2264ced8de1STim Renouf 
elementllvm::yaml::SequenceTraits2274ced8de1STim Renouf   static DocNode &element(IO &IO, ArrayDocNode &A, size_t Index) {
2284ced8de1STim Renouf     return A[Index];
2294ced8de1STim Renouf   }
2304ced8de1STim Renouf };
2314ced8de1STim Renouf 
2324ced8de1STim Renouf } // namespace yaml
2334ced8de1STim Renouf } // namespace llvm
2344ced8de1STim Renouf 
2354ced8de1STim Renouf /// Convert MsgPack Document to YAML text.
toYAML(raw_ostream & OS)2364ced8de1STim Renouf void msgpack::Document::toYAML(raw_ostream &OS) {
2374ced8de1STim Renouf   yaml::Output Yout(OS);
2384ced8de1STim Renouf   Yout << getRoot();
2394ced8de1STim Renouf }
2404ced8de1STim Renouf 
2414ced8de1STim Renouf /// Read YAML text into the MsgPack document. Returns false on failure.
fromYAML(StringRef S)2424ced8de1STim Renouf bool msgpack::Document::fromYAML(StringRef S) {
2434ced8de1STim Renouf   clear();
2444ced8de1STim Renouf   yaml::Input Yin(S);
2454ced8de1STim Renouf   Yin >> getRoot();
2464ced8de1STim Renouf   return !Yin.error();
2474ced8de1STim Renouf }
2484ced8de1STim Renouf 
249