brintos

brintos / llvm-project-archived public Read only

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