diff --git a/llvm/lib/BinaryFormat/MsgPackDocumentYAML.cpp b/llvm/lib/BinaryFormat/MsgPackDocumentYAML.cpp index 80b421d5f752e..fbf871f709a64 100644 --- a/llvm/lib/BinaryFormat/MsgPackDocumentYAML.cpp +++ b/llvm/lib/BinaryFormat/MsgPackDocumentYAML.cpp @@ -29,6 +29,10 @@ struct ScalarDocNode : DocNode { StringRef getYAMLTag() const; }; +bool isJSONSchemaBoolLiteral(StringRef S) { + return S == "true" || S == "false"; +} + } // namespace /// Convert this DocNode to a string, assuming it is scalar. @@ -84,11 +88,18 @@ StringRef DocNode::fromString(StringRef S, StringRef Tag) { *this = getDocument()->getNode(); return ""; } - if (Tag == "!bool" || Tag == "") { + if (Tag == "!bool") { *this = getDocument()->getNode(false); - StringRef Err = yaml::ScalarTraits::input(S, nullptr, getBool()); - if (Err == "" || Tag != "") - return Err; + return yaml::ScalarTraits::input(S, nullptr, getBool()); + } + // FIXME: This enforces the "JSON Schema" tag resolution for boolean literals, + // defined at https://yaml.org/spec/1.2.2/#json-schema which we adopt because + // the more general pre-1.2 resolution includes many common strings (e.g. "n", + // "no", "y", "yes", ...). This should be handled at the YAMLTraits level, but + // that change would have a much broader impact. + if (Tag == "" && isJSONSchemaBoolLiteral(S)) { + *this = getDocument()->getNode(S == "true"); + return ""; } if (Tag == "!float" || Tag == "") { *this = getDocument()->getNode(0.0); diff --git a/llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp b/llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp index 6a6ad7010f629..60b2b28c7fac9 100644 --- a/llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp +++ b/llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp @@ -420,3 +420,89 @@ TEST(MsgPackDocument, TestInputYAMLMap) { ASSERT_EQ(SS.getKind(), Type::String); ASSERT_EQ(SS.getString(), "2"); } + +TEST(MsgPackDocument, TestYAMLBoolean) { + Document Doc; + auto GetFirst = [](Document &Doc) { return Doc.getRoot().getArray()[0]; }; + auto ToYAML = [](Document &Doc) { + std::string S; + raw_string_ostream OS(S); + Doc.toYAML(OS); + return S; + }; + + bool Ok; + + Ok = Doc.fromYAML("- n\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::String); + ASSERT_EQ(GetFirst(Doc).getString(), "n"); + ASSERT_EQ(ToYAML(Doc), "---\n- n\n...\n"); + + Ok = Doc.fromYAML("- y\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::String); + ASSERT_EQ(GetFirst(Doc).getString(), "y"); + ASSERT_EQ(ToYAML(Doc), "---\n- y\n...\n"); + + Ok = Doc.fromYAML("- no\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::String); + ASSERT_EQ(GetFirst(Doc).getString(), "no"); + ASSERT_EQ(ToYAML(Doc), "---\n- no\n...\n"); + + Ok = Doc.fromYAML("- yes\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::String); + ASSERT_EQ(GetFirst(Doc).getString(), "yes"); + ASSERT_EQ(ToYAML(Doc), "---\n- yes\n...\n"); + + Ok = Doc.fromYAML("- false\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean); + ASSERT_EQ(GetFirst(Doc).getBool(), false); + ASSERT_EQ(ToYAML(Doc), "---\n- false\n...\n"); + + Ok = Doc.fromYAML("- true\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean); + ASSERT_EQ(GetFirst(Doc).getBool(), true); + ASSERT_EQ(ToYAML(Doc), "---\n- true\n...\n"); + + Ok = Doc.fromYAML("- !str false\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::String); + ASSERT_EQ(GetFirst(Doc).getString(), "false"); + ASSERT_EQ(ToYAML(Doc), "---\n- !str 'false'\n...\n"); + + Ok = Doc.fromYAML("- !str true\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::String); + ASSERT_EQ(GetFirst(Doc).getString(), "true"); + ASSERT_EQ(ToYAML(Doc), "---\n- !str 'true'\n...\n"); + + Ok = Doc.fromYAML("- !bool false\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean); + ASSERT_EQ(GetFirst(Doc).getBool(), false); + ASSERT_EQ(ToYAML(Doc), "---\n- false\n...\n"); + + Ok = Doc.fromYAML("- !bool true\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean); + ASSERT_EQ(GetFirst(Doc).getBool(), true); + ASSERT_EQ(ToYAML(Doc), "---\n- true\n...\n"); + + // FIXME: A fix for these requires changes in YAMLParser/YAMLTraits. + Ok = Doc.fromYAML("- \"false\"\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean); + ASSERT_EQ(GetFirst(Doc).getBool(), false); + ASSERT_EQ(ToYAML(Doc), "---\n- false\n...\n"); + + Ok = Doc.fromYAML("- \"true\"\n"); + ASSERT_TRUE(Ok); + ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean); + ASSERT_EQ(GetFirst(Doc).getBool(), true); + ASSERT_EQ(ToYAML(Doc), "---\n- true\n...\n"); +}