MsgPackDocumentYAML.cpp 7.1 KB

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