Path: blob/main/contrib/llvm-project/llvm/lib/BinaryFormat/MsgPackDocumentYAML.cpp
35234 views
//===-- MsgPackDocumentYAML.cpp - MsgPack Document YAML interface -------*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// This file implements YAMLIO on a msgpack::Document.9//10//===----------------------------------------------------------------------===//1112#include "llvm/BinaryFormat/MsgPackDocument.h"13#include "llvm/Support/YAMLTraits.h"1415using namespace llvm;16using namespace msgpack;1718namespace {1920// Struct used to represent scalar node. (MapDocNode and ArrayDocNode already21// exist in MsgPackDocument.h.)22struct ScalarDocNode : DocNode {23ScalarDocNode(DocNode N) : DocNode(N) {}2425/// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only26/// returns something else if the result of toString would be ambiguous, e.g.27/// a string that parses as a number or boolean.28StringRef getYAMLTag() const;29};3031} // namespace3233/// Convert this DocNode to a string, assuming it is scalar.34std::string DocNode::toString() const {35std::string S;36raw_string_ostream OS(S);37switch (getKind()) {38case msgpack::Type::String:39OS << Raw;40break;41case msgpack::Type::Nil:42break;43case msgpack::Type::Boolean:44OS << (Bool ? "true" : "false");45break;46case msgpack::Type::Int:47OS << Int;48break;49case msgpack::Type::UInt:50if (getDocument()->getHexMode())51OS << format("%#llx", (unsigned long long)UInt);52else53OS << UInt;54break;55case msgpack::Type::Float:56OS << Float;57break;58default:59llvm_unreachable("not scalar");60break;61}62return OS.str();63}6465/// Convert the StringRef and use it to set this DocNode (assuming scalar). If66/// it is a string, copy the string into the Document's strings list so we do67/// not rely on S having a lifetime beyond this call. Tag is "" or a YAML tag.68StringRef DocNode::fromString(StringRef S, StringRef Tag) {69if (Tag == "tag:yaml.org,2002:str")70Tag = "";71if (Tag == "!int" || Tag == "") {72// Try unsigned int then signed int.73*this = getDocument()->getNode(uint64_t(0));74StringRef Err = yaml::ScalarTraits<uint64_t>::input(S, nullptr, getUInt());75if (Err != "") {76*this = getDocument()->getNode(int64_t(0));77Err = yaml::ScalarTraits<int64_t>::input(S, nullptr, getInt());78}79if (Err == "" || Tag != "")80return Err;81}82if (Tag == "!nil") {83*this = getDocument()->getNode();84return "";85}86if (Tag == "!bool" || Tag == "") {87*this = getDocument()->getNode(false);88StringRef Err = yaml::ScalarTraits<bool>::input(S, nullptr, getBool());89if (Err == "" || Tag != "")90return Err;91}92if (Tag == "!float" || Tag == "") {93*this = getDocument()->getNode(0.0);94StringRef Err = yaml::ScalarTraits<double>::input(S, nullptr, getFloat());95if (Err == "" || Tag != "")96return Err;97}98assert((Tag == "!str" || Tag == "") && "unsupported tag");99std::string V;100StringRef Err = yaml::ScalarTraits<std::string>::input(S, nullptr, V);101if (Err == "")102*this = getDocument()->getNode(V, /*Copy=*/true);103return Err;104}105106/// Get the YAML tag for this ScalarDocNode. This normally returns ""; it only107/// returns something else if the result of toString would be ambiguous, e.g.108/// a string that parses as a number or boolean.109StringRef ScalarDocNode::getYAMLTag() const {110if (getKind() == msgpack::Type::Nil)111return "!nil";112// Try converting both ways and see if we get the same kind. If not, we need113// a tag.114ScalarDocNode N = getDocument()->getNode();115N.fromString(toString(), "");116if (N.getKind() == getKind())117return "";118// Tolerate signedness of int changing, as tags do not differentiate between119// them anyway.120if (N.getKind() == msgpack::Type::UInt && getKind() == msgpack::Type::Int)121return "";122if (N.getKind() == msgpack::Type::Int && getKind() == msgpack::Type::UInt)123return "";124// We do need a tag.125switch (getKind()) {126case msgpack::Type::String:127return "!str";128case msgpack::Type::Int:129return "!int";130case msgpack::Type::UInt:131return "!int";132case msgpack::Type::Boolean:133return "!bool";134case msgpack::Type::Float:135return "!float";136default:137llvm_unreachable("unrecognized kind");138}139}140141namespace llvm {142namespace yaml {143144/// YAMLIO for DocNode145template <> struct PolymorphicTraits<DocNode> {146147static NodeKind getKind(const DocNode &N) {148switch (N.getKind()) {149case msgpack::Type::Map:150return NodeKind::Map;151case msgpack::Type::Array:152return NodeKind::Sequence;153default:154return NodeKind::Scalar;155}156}157158static MapDocNode &getAsMap(DocNode &N) { return N.getMap(/*Convert=*/true); }159160static ArrayDocNode &getAsSequence(DocNode &N) {161N.getArray(/*Convert=*/true);162return *static_cast<ArrayDocNode *>(&N);163}164165static ScalarDocNode &getAsScalar(DocNode &N) {166return *static_cast<ScalarDocNode *>(&N);167}168};169170/// YAMLIO for ScalarDocNode171template <> struct TaggedScalarTraits<ScalarDocNode> {172173static void output(const ScalarDocNode &S, void *Ctxt, raw_ostream &OS,174raw_ostream &TagOS) {175TagOS << S.getYAMLTag();176OS << S.toString();177}178179static StringRef input(StringRef Str, StringRef Tag, void *Ctxt,180ScalarDocNode &S) {181return S.fromString(Str, Tag);182}183184static QuotingType mustQuote(const ScalarDocNode &S, StringRef ScalarStr) {185switch (S.getKind()) {186case Type::Int:187return ScalarTraits<int64_t>::mustQuote(ScalarStr);188case Type::UInt:189return ScalarTraits<uint64_t>::mustQuote(ScalarStr);190case Type::Nil:191return ScalarTraits<StringRef>::mustQuote(ScalarStr);192case Type::Boolean:193return ScalarTraits<bool>::mustQuote(ScalarStr);194case Type::Float:195return ScalarTraits<double>::mustQuote(ScalarStr);196case Type::Binary:197case Type::String:198return ScalarTraits<std::string>::mustQuote(ScalarStr);199default:200llvm_unreachable("unrecognized ScalarKind");201}202}203};204205/// YAMLIO for MapDocNode206template <> struct CustomMappingTraits<MapDocNode> {207208static void inputOne(IO &IO, StringRef Key, MapDocNode &M) {209ScalarDocNode KeyObj = M.getDocument()->getNode();210KeyObj.fromString(Key, "");211IO.mapRequired(Key.str().c_str(), M.getMap()[KeyObj]);212}213214static void output(IO &IO, MapDocNode &M) {215for (auto I : M.getMap()) {216IO.mapRequired(I.first.toString().c_str(), I.second);217}218}219};220221/// YAMLIO for ArrayNode222template <> struct SequenceTraits<ArrayDocNode> {223224static size_t size(IO &IO, ArrayDocNode &A) { return A.size(); }225226static DocNode &element(IO &IO, ArrayDocNode &A, size_t Index) {227return A[Index];228}229};230231} // namespace yaml232} // namespace llvm233234/// Convert MsgPack Document to YAML text.235void msgpack::Document::toYAML(raw_ostream &OS) {236yaml::Output Yout(OS);237Yout << getRoot();238}239240/// Read YAML text into the MsgPack document. Returns false on failure.241bool msgpack::Document::fromYAML(StringRef S) {242clear();243yaml::Input Yin(S);244Yin >> getRoot();245return !Yin.error();246}247248249250