1 //===-- MsgPackDocumentYAML.cpp - MsgPack Document YAML interface -------*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 /// This file implements YAMLIO on a msgpack::Document.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/BinaryFormat/MsgPackDocument.h"
14 #include "llvm/Support/YAMLTraits.h"
17 using namespace msgpack
;
21 // Struct used to represent scalar node. (MapDocNode and ArrayDocNode already
22 // exist in MsgPackDocument.h.)
23 struct ScalarDocNode
: DocNode
{
24 ScalarDocNode(DocNode N
) : DocNode(N
) {}
26 /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
27 /// returns something else if the result of toString would be ambiguous, e.g.
28 /// a string that parses as a number or boolean.
29 StringRef
getYAMLTag() const;
34 /// Convert this DocNode to a string, assuming it is scalar.
35 std::string
DocNode::toString() const {
37 raw_string_ostream
OS(S
);
39 case msgpack::Type::String
:
42 case msgpack::Type::Nil
:
44 case msgpack::Type::Boolean
:
45 OS
<< (Bool
? "true" : "false");
47 case msgpack::Type::Int
:
50 case msgpack::Type::UInt
:
51 if (getDocument()->getHexMode())
52 OS
<< format("%#llx", (unsigned long long)UInt
);
56 case msgpack::Type::Float
:
60 llvm_unreachable("not scalar");
66 /// Convert the StringRef and use it to set this DocNode (assuming scalar). If
67 /// it is a string, copy the string into the Document's strings list so we do
68 /// not rely on S having a lifetime beyond this call. Tag is "" or a YAML tag.
69 StringRef
DocNode::fromString(StringRef S
, StringRef Tag
) {
70 if (Tag
== "tag:yaml.org,2002:str")
72 if (Tag
== "!int" || Tag
== "") {
73 // Try unsigned int then signed int.
74 *this = getDocument()->getNode(uint64_t(0));
75 StringRef Err
= yaml::ScalarTraits
<uint64_t>::input(S
, nullptr, getUInt());
77 *this = getDocument()->getNode(int64_t(0));
78 Err
= yaml::ScalarTraits
<int64_t>::input(S
, nullptr, getInt());
80 if (Err
== "" || Tag
!= "")
84 *this = getDocument()->getNode();
87 if (Tag
== "!bool" || Tag
== "") {
88 *this = getDocument()->getNode(false);
89 StringRef Err
= yaml::ScalarTraits
<bool>::input(S
, nullptr, getBool());
90 if (Err
== "" || Tag
!= "")
93 if (Tag
== "!float" || Tag
== "") {
94 *this = getDocument()->getNode(0.0);
95 StringRef Err
= yaml::ScalarTraits
<double>::input(S
, nullptr, getFloat());
96 if (Err
== "" || Tag
!= "")
99 assert((Tag
== "!str" || Tag
== "") && "unsupported tag");
101 StringRef Err
= yaml::ScalarTraits
<std::string
>::input(S
, nullptr, V
);
103 *this = getDocument()->getNode(V
, /*Copy=*/true);
107 /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
108 /// returns something else if the result of toString would be ambiguous, e.g.
109 /// a string that parses as a number or boolean.
110 StringRef
ScalarDocNode::getYAMLTag() const {
111 if (getKind() == msgpack::Type::Nil
)
113 // Try converting both ways and see if we get the same kind. If not, we need
115 ScalarDocNode N
= getDocument()->getNode();
116 N
.fromString(toString(), "");
117 if (N
.getKind() == getKind())
119 // Tolerate signedness of int changing, as tags do not differentiate between
121 if (N
.getKind() == msgpack::Type::UInt
&& getKind() == msgpack::Type::Int
)
123 if (N
.getKind() == msgpack::Type::Int
&& getKind() == msgpack::Type::UInt
)
127 case msgpack::Type::String
:
129 case msgpack::Type::Int
:
131 case msgpack::Type::UInt
:
133 case msgpack::Type::Boolean
:
135 case msgpack::Type::Float
:
138 llvm_unreachable("unrecognized kind");
145 /// YAMLIO for DocNode
146 template <> struct PolymorphicTraits
<DocNode
> {
148 static NodeKind
getKind(const DocNode
&N
) {
149 switch (N
.getKind()) {
150 case msgpack::Type::Map
:
151 return NodeKind::Map
;
152 case msgpack::Type::Array
:
153 return NodeKind::Sequence
;
155 return NodeKind::Scalar
;
159 static MapDocNode
&getAsMap(DocNode
&N
) { return N
.getMap(/*Convert=*/true); }
161 static ArrayDocNode
&getAsSequence(DocNode
&N
) {
162 N
.getArray(/*Convert=*/true);
163 return *static_cast<ArrayDocNode
*>(&N
);
166 static ScalarDocNode
&getAsScalar(DocNode
&N
) {
167 return *static_cast<ScalarDocNode
*>(&N
);
171 /// YAMLIO for ScalarDocNode
172 template <> struct TaggedScalarTraits
<ScalarDocNode
> {
174 static void output(const ScalarDocNode
&S
, void *Ctxt
, raw_ostream
&OS
,
175 raw_ostream
&TagOS
) {
176 TagOS
<< S
.getYAMLTag();
180 static StringRef
input(StringRef Str
, StringRef Tag
, void *Ctxt
,
182 return S
.fromString(Str
, Tag
);
185 static QuotingType
mustQuote(const ScalarDocNode
&S
, StringRef ScalarStr
) {
186 switch (S
.getKind()) {
188 return ScalarTraits
<int64_t>::mustQuote(ScalarStr
);
190 return ScalarTraits
<uint64_t>::mustQuote(ScalarStr
);
192 return ScalarTraits
<StringRef
>::mustQuote(ScalarStr
);
194 return ScalarTraits
<bool>::mustQuote(ScalarStr
);
196 return ScalarTraits
<double>::mustQuote(ScalarStr
);
199 return ScalarTraits
<std::string
>::mustQuote(ScalarStr
);
201 llvm_unreachable("unrecognized ScalarKind");
206 /// YAMLIO for MapDocNode
207 template <> struct CustomMappingTraits
<MapDocNode
> {
209 static void inputOne(IO
&IO
, StringRef Key
, MapDocNode
&M
) {
210 ScalarDocNode KeyObj
= M
.getDocument()->getNode();
211 KeyObj
.fromString(Key
, "");
212 IO
.mapRequired(Key
.str().c_str(), M
.getMap()[KeyObj
]);
215 static void output(IO
&IO
, MapDocNode
&M
) {
216 for (auto I
: M
.getMap()) {
217 IO
.mapRequired(I
.first
.toString().c_str(), I
.second
);
222 /// YAMLIO for ArrayNode
223 template <> struct SequenceTraits
<ArrayDocNode
> {
225 static size_t size(IO
&IO
, ArrayDocNode
&A
) { return A
.size(); }
227 static DocNode
&element(IO
&IO
, ArrayDocNode
&A
, size_t Index
) {
235 /// Convert MsgPack Document to YAML text.
236 void msgpack::Document::toYAML(raw_ostream
&OS
) {
237 yaml::Output
Yout(OS
);
241 /// Read YAML text into the MsgPack document. Returns false on failure.
242 bool msgpack::Document::fromYAML(StringRef S
) {