1 //===-- MsgPackDocumentYAML.cpp - MsgPack Document YAML interface -------*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 /// This file implements YAMLIO on a msgpack::Document.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/BinaryFormat/MsgPackDocument.h"
15 #include "llvm/Support/YAMLTraits.h"
18 using namespace msgpack
;
22 // Struct used to represent scalar node. (MapDocNode and ArrayDocNode already
23 // exist in MsgPackDocument.h.)
24 struct ScalarDocNode
: DocNode
{
25 ScalarDocNode(DocNode N
) : DocNode(N
) {}
27 /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
28 /// returns something else if the result of toString would be ambiguous, e.g.
29 /// a string that parses as a number or boolean.
30 StringRef
getYAMLTag() const;
35 /// Convert this DocNode to a string, assuming it is scalar.
36 std::string
DocNode::toString() const {
38 raw_string_ostream
OS(S
);
40 case msgpack::Type::String
:
43 case msgpack::Type::Nil
:
45 case msgpack::Type::Boolean
:
46 OS
<< (Bool
? "true" : "false");
48 case msgpack::Type::Int
:
51 case msgpack::Type::UInt
:
52 if (getDocument()->getHexMode())
53 OS
<< format("%#llx", (unsigned long long)UInt
);
57 case msgpack::Type::Float
:
61 llvm_unreachable("not scalar");
67 /// Convert the StringRef and use it to set this DocNode (assuming scalar). If
68 /// it is a string, copy the string into the Document's strings list so we do
69 /// not rely on S having a lifetime beyond this call. Tag is "" or a YAML tag.
70 StringRef
DocNode::fromString(StringRef S
, StringRef Tag
) {
71 if (Tag
== "tag:yaml.org,2002:str")
73 if (Tag
== "!int" || Tag
== "") {
74 // Try unsigned int then signed int.
75 *this = getDocument()->getNode(uint64_t(0));
76 StringRef Err
= yaml::ScalarTraits
<uint64_t>::input(S
, nullptr, getUInt());
78 *this = getDocument()->getNode(int64_t(0));
79 Err
= yaml::ScalarTraits
<int64_t>::input(S
, nullptr, getInt());
81 if (Err
== "" || Tag
!= "")
85 *this = getDocument()->getNode();
88 if (Tag
== "!bool" || Tag
== "") {
89 *this = getDocument()->getNode(false);
90 StringRef Err
= yaml::ScalarTraits
<bool>::input(S
, nullptr, getBool());
91 if (Err
== "" || Tag
!= "")
94 if (Tag
== "!float" || Tag
== "") {
95 *this = getDocument()->getNode(0.0);
96 StringRef Err
= yaml::ScalarTraits
<double>::input(S
, nullptr, getFloat());
97 if (Err
== "" || Tag
!= "")
100 assert((Tag
== "!str" || Tag
== "") && "unsupported tag");
102 StringRef Err
= yaml::ScalarTraits
<std::string
>::input(S
, nullptr, V
);
104 *this = getDocument()->getNode(V
, /*Copy=*/true);
108 /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
109 /// returns something else if the result of toString would be ambiguous, e.g.
110 /// a string that parses as a number or boolean.
111 StringRef
ScalarDocNode::getYAMLTag() const {
112 if (getKind() == msgpack::Type::Nil
)
114 // Try converting both ways and see if we get the same kind. If not, we need
116 ScalarDocNode N
= getDocument()->getNode();
117 N
.fromString(toString(), "");
118 if (N
.getKind() == getKind())
120 // Tolerate signedness of int changing, as tags do not differentiate between
122 if (N
.getKind() == msgpack::Type::UInt
&& getKind() == msgpack::Type::Int
)
124 if (N
.getKind() == msgpack::Type::Int
&& getKind() == msgpack::Type::UInt
)
128 case msgpack::Type::String
:
130 case msgpack::Type::Int
:
132 case msgpack::Type::UInt
:
134 case msgpack::Type::Boolean
:
136 case msgpack::Type::Float
:
139 llvm_unreachable("unrecognized kind");
146 /// YAMLIO for DocNode
147 template <> struct PolymorphicTraits
<DocNode
> {
149 static NodeKind
getKind(const DocNode
&N
) {
150 switch (N
.getKind()) {
151 case msgpack::Type::Map
:
152 return NodeKind::Map
;
153 case msgpack::Type::Array
:
154 return NodeKind::Sequence
;
156 return NodeKind::Scalar
;
160 static MapDocNode
&getAsMap(DocNode
&N
) { return N
.getMap(/*Convert=*/true); }
162 static ArrayDocNode
&getAsSequence(DocNode
&N
) {
163 N
.getArray(/*Convert=*/true);
164 return *static_cast<ArrayDocNode
*>(&N
);
167 static ScalarDocNode
&getAsScalar(DocNode
&N
) {
168 return *static_cast<ScalarDocNode
*>(&N
);
172 /// YAMLIO for ScalarDocNode
173 template <> struct TaggedScalarTraits
<ScalarDocNode
> {
175 static void output(const ScalarDocNode
&S
, void *Ctxt
, raw_ostream
&OS
,
176 raw_ostream
&TagOS
) {
177 TagOS
<< S
.getYAMLTag();
181 static StringRef
input(StringRef Str
, StringRef Tag
, void *Ctxt
,
183 return S
.fromString(Str
, Tag
);
186 static QuotingType
mustQuote(const ScalarDocNode
&S
, StringRef ScalarStr
) {
187 switch (S
.getKind()) {
189 return ScalarTraits
<int64_t>::mustQuote(ScalarStr
);
191 return ScalarTraits
<uint64_t>::mustQuote(ScalarStr
);
193 return ScalarTraits
<StringRef
>::mustQuote(ScalarStr
);
195 return ScalarTraits
<bool>::mustQuote(ScalarStr
);
197 return ScalarTraits
<double>::mustQuote(ScalarStr
);
200 return ScalarTraits
<std::string
>::mustQuote(ScalarStr
);
202 llvm_unreachable("unrecognized ScalarKind");
207 /// YAMLIO for MapDocNode
208 template <> struct CustomMappingTraits
<MapDocNode
> {
210 static void inputOne(IO
&IO
, StringRef Key
, MapDocNode
&M
) {
211 ScalarDocNode KeyObj
= M
.getDocument()->getNode();
212 KeyObj
.fromString(Key
, "");
213 IO
.mapRequired(Key
.str().c_str(), M
.getMap()[KeyObj
]);
216 static void output(IO
&IO
, MapDocNode
&M
) {
217 for (auto I
: M
.getMap()) {
218 IO
.mapRequired(I
.first
.toString().c_str(), I
.second
);
223 /// YAMLIO for ArrayNode
224 template <> struct SequenceTraits
<ArrayDocNode
> {
226 static size_t size(IO
&IO
, ArrayDocNode
&A
) { return A
.size(); }
228 static DocNode
&element(IO
&IO
, ArrayDocNode
&A
, size_t Index
) {
236 /// Convert MsgPack Document to YAML text.
237 void msgpack::Document::toYAML(raw_ostream
&OS
) {
238 yaml::Output
Yout(OS
);
242 /// Read YAML text into the MsgPack document. Returns false on failure.
243 bool msgpack::Document::fromYAML(StringRef S
) {