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