MsgPackDocumentYAML.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. //===-- MsgPackDocumentYAML.cpp - MsgPack Document YAML interface -------*-===//
  2. //
  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
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. /// This file implements YAMLIO on a msgpack::Document.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "llvm/BinaryFormat/MsgPackDocument.h"
  13. #include "llvm/Support/YAMLTraits.h"
  14. using namespace llvm;
  15. using namespace msgpack;
  16. namespace {
  17. // Struct used to represent scalar node. (MapDocNode and ArrayDocNode already
  18. // exist in MsgPackDocument.h.)
  19. struct ScalarDocNode : DocNode {
  20. ScalarDocNode(DocNode N) : DocNode(N) {}
  21. /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
  22. /// returns something else if the result of toString would be ambiguous, e.g.
  23. /// a string that parses as a number or boolean.
  24. StringRef getYAMLTag() const;
  25. };
  26. } // namespace
  27. /// Convert this DocNode to a string, assuming it is scalar.
  28. std::string DocNode::toString() const {
  29. std::string S;
  30. raw_string_ostream OS(S);
  31. switch (getKind()) {
  32. case msgpack::Type::String:
  33. OS << Raw;
  34. break;
  35. case msgpack::Type::Nil:
  36. break;
  37. case msgpack::Type::Boolean:
  38. OS << (Bool ? "true" : "false");
  39. break;
  40. case msgpack::Type::Int:
  41. OS << Int;
  42. break;
  43. case msgpack::Type::UInt:
  44. if (getDocument()->getHexMode())
  45. OS << format("%#llx", (unsigned long long)UInt);
  46. else
  47. OS << UInt;
  48. break;
  49. case msgpack::Type::Float:
  50. OS << Float;
  51. break;
  52. default:
  53. llvm_unreachable("not scalar");
  54. break;
  55. }
  56. return OS.str();
  57. }
  58. /// Convert the StringRef and use it to set this DocNode (assuming scalar). If
  59. /// it is a string, copy the string into the Document's strings list so we do
  60. /// not rely on S having a lifetime beyond this call. Tag is "" or a YAML tag.
  61. StringRef DocNode::fromString(StringRef S, StringRef Tag) {
  62. if (Tag == "tag:yaml.org,2002:str")
  63. Tag = "";
  64. if (Tag == "!int" || Tag == "") {
  65. // Try unsigned int then signed int.
  66. *this = getDocument()->getNode(uint64_t(0));
  67. StringRef Err = yaml::ScalarTraits<uint64_t>::input(S, nullptr, getUInt());
  68. if (Err != "") {
  69. *this = getDocument()->getNode(int64_t(0));
  70. Err = yaml::ScalarTraits<int64_t>::input(S, nullptr, getInt());
  71. }
  72. if (Err == "" || Tag != "")
  73. return Err;
  74. }
  75. if (Tag == "!nil") {
  76. *this = getDocument()->getNode();
  77. return "";
  78. }
  79. if (Tag == "!bool" || Tag == "") {
  80. *this = getDocument()->getNode(false);
  81. StringRef Err = yaml::ScalarTraits<bool>::input(S, nullptr, getBool());
  82. if (Err == "" || Tag != "")
  83. return Err;
  84. }
  85. if (Tag == "!float" || Tag == "") {
  86. *this = getDocument()->getNode(0.0);
  87. StringRef Err = yaml::ScalarTraits<double>::input(S, nullptr, getFloat());
  88. if (Err == "" || Tag != "")
  89. return Err;
  90. }
  91. assert((Tag == "!str" || Tag == "") && "unsupported tag");
  92. std::string V;
  93. StringRef Err = yaml::ScalarTraits<std::string>::input(S, nullptr, V);
  94. if (Err == "")
  95. *this = getDocument()->getNode(V, /*Copy=*/true);
  96. return Err;
  97. }
  98. /// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only
  99. /// returns something else if the result of toString would be ambiguous, e.g.
  100. /// a string that parses as a number or boolean.
  101. StringRef ScalarDocNode::getYAMLTag() const {
  102. if (getKind() == msgpack::Type::Nil)
  103. return "!nil";
  104. // Try converting both ways and see if we get the same kind. If not, we need
  105. // a tag.
  106. ScalarDocNode N = getDocument()->getNode();
  107. N.fromString(toString(), "");
  108. if (N.getKind() == getKind())
  109. return "";
  110. // Tolerate signedness of int changing, as tags do not differentiate between
  111. // them anyway.
  112. if (N.getKind() == msgpack::Type::UInt && getKind() == msgpack::Type::Int)
  113. return "";
  114. if (N.getKind() == msgpack::Type::Int && getKind() == msgpack::Type::UInt)
  115. return "";
  116. // We do need a tag.
  117. switch (getKind()) {
  118. case msgpack::Type::String:
  119. return "!str";
  120. case msgpack::Type::Int:
  121. return "!int";
  122. case msgpack::Type::UInt:
  123. return "!int";
  124. case msgpack::Type::Boolean:
  125. return "!bool";
  126. case msgpack::Type::Float:
  127. return "!float";
  128. default:
  129. llvm_unreachable("unrecognized kind");
  130. }
  131. }
  132. namespace llvm {
  133. namespace yaml {
  134. /// YAMLIO for DocNode
  135. template <> struct PolymorphicTraits<DocNode> {
  136. static NodeKind getKind(const DocNode &N) {
  137. switch (N.getKind()) {
  138. case msgpack::Type::Map:
  139. return NodeKind::Map;
  140. case msgpack::Type::Array:
  141. return NodeKind::Sequence;
  142. default:
  143. return NodeKind::Scalar;
  144. }
  145. }
  146. static MapDocNode &getAsMap(DocNode &N) { return N.getMap(/*Convert=*/true); }
  147. static ArrayDocNode &getAsSequence(DocNode &N) {
  148. N.getArray(/*Convert=*/true);
  149. return *static_cast<ArrayDocNode *>(&N);
  150. }
  151. static ScalarDocNode &getAsScalar(DocNode &N) {
  152. return *static_cast<ScalarDocNode *>(&N);
  153. }
  154. };
  155. /// YAMLIO for ScalarDocNode
  156. template <> struct TaggedScalarTraits<ScalarDocNode> {
  157. static void output(const ScalarDocNode &S, void *Ctxt, raw_ostream &OS,
  158. raw_ostream &TagOS) {
  159. TagOS << S.getYAMLTag();
  160. OS << S.toString();
  161. }
  162. static StringRef input(StringRef Str, StringRef Tag, void *Ctxt,
  163. ScalarDocNode &S) {
  164. return S.fromString(Str, Tag);
  165. }
  166. static QuotingType mustQuote(const ScalarDocNode &S, StringRef ScalarStr) {
  167. switch (S.getKind()) {
  168. case Type::Int:
  169. return ScalarTraits<int64_t>::mustQuote(ScalarStr);
  170. case Type::UInt:
  171. return ScalarTraits<uint64_t>::mustQuote(ScalarStr);
  172. case Type::Nil:
  173. return ScalarTraits<StringRef>::mustQuote(ScalarStr);
  174. case Type::Boolean:
  175. return ScalarTraits<bool>::mustQuote(ScalarStr);
  176. case Type::Float:
  177. return ScalarTraits<double>::mustQuote(ScalarStr);
  178. case Type::Binary:
  179. case Type::String:
  180. return ScalarTraits<std::string>::mustQuote(ScalarStr);
  181. default:
  182. llvm_unreachable("unrecognized ScalarKind");
  183. }
  184. }
  185. };
  186. /// YAMLIO for MapDocNode
  187. template <> struct CustomMappingTraits<MapDocNode> {
  188. static void inputOne(IO &IO, StringRef Key, MapDocNode &M) {
  189. ScalarDocNode KeyObj = M.getDocument()->getNode();
  190. KeyObj.fromString(Key, "");
  191. IO.mapRequired(Key.str().c_str(), M.getMap()[KeyObj]);
  192. }
  193. static void output(IO &IO, MapDocNode &M) {
  194. for (auto I : M.getMap()) {
  195. IO.mapRequired(I.first.toString().c_str(), I.second);
  196. }
  197. }
  198. };
  199. /// YAMLIO for ArrayNode
  200. template <> struct SequenceTraits<ArrayDocNode> {
  201. static size_t size(IO &IO, ArrayDocNode &A) { return A.size(); }
  202. static DocNode &element(IO &IO, ArrayDocNode &A, size_t Index) {
  203. return A[Index];
  204. }
  205. };
  206. } // namespace yaml
  207. } // namespace llvm
  208. /// Convert MsgPack Document to YAML text.
  209. void msgpack::Document::toYAML(raw_ostream &OS) {
  210. yaml::Output Yout(OS);
  211. Yout << getRoot();
  212. }
  213. /// Read YAML text into the MsgPack document. Returns false on failure.
  214. bool msgpack::Document::fromYAML(StringRef S) {
  215. clear();
  216. yaml::Input Yin(S);
  217. Yin >> getRoot();
  218. return !Yin.error();
  219. }