Skip to content

Commit 3b29886

Browse files
committed
[MsgPack] Use JSON schema boolean resolution rules
Since YAMLIO generally knows the types ahead of time (since it primarily functions to (de)serialize concrete C++ types) "tag resolution" isn't really a meaningful isssue. With MsgPackDocument we permit arbitrary documents with arbitrary type nodes, and so the YAML "NO" problem is an issue. Address this in MsgPackDocument itself to avoid a significant and far-reaching backwards-incompatible change to YAMLIO (although we could still consider tightening things up there in the future). Use the "JSON Schema" for tag resolution where the only literals to resolve to bool by default are "true" and "false".
1 parent 1054a6e commit 3b29886

File tree

2 files changed

+89
-4
lines changed

2 files changed

+89
-4
lines changed

llvm/lib/BinaryFormat/MsgPackDocumentYAML.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ struct ScalarDocNode : DocNode {
2929
StringRef getYAMLTag() const;
3030
};
3131

32+
bool isJSONSchemaBoolLiteral(StringRef S) {
33+
return S == "true" || S == "false";
34+
}
35+
3236
} // namespace
3337

3438
/// Convert this DocNode to a string, assuming it is scalar.
@@ -84,11 +88,18 @@ StringRef DocNode::fromString(StringRef S, StringRef Tag) {
8488
*this = getDocument()->getNode();
8589
return "";
8690
}
87-
if (Tag == "!bool" || Tag == "") {
91+
if (Tag == "!bool") {
8892
*this = getDocument()->getNode(false);
89-
StringRef Err = yaml::ScalarTraits<bool>::input(S, nullptr, getBool());
90-
if (Err == "" || Tag != "")
91-
return Err;
93+
return yaml::ScalarTraits<bool>::input(S, nullptr, getBool());
94+
}
95+
// FIXME: This enforces the "JSON Schema" tag resolution for boolean literals,
96+
// defined at https://yaml.org/spec/1.2.2/#json-schema which we adopt because
97+
// the more general pre-1.2 resolution includes many common strings (e.g. "n",
98+
// "no", "y", "yes", ...). This should be handled at the YAMLTraits level, but
99+
// that change would have a much broader impact.
100+
if (Tag == "" && isJSONSchemaBoolLiteral(S)) {
101+
*this = getDocument()->getNode(S == "true");
102+
return "";
92103
}
93104
if (Tag == "!float" || Tag == "") {
94105
*this = getDocument()->getNode(0.0);

llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,3 +420,77 @@ TEST(MsgPackDocument, TestInputYAMLMap) {
420420
ASSERT_EQ(SS.getKind(), Type::String);
421421
ASSERT_EQ(SS.getString(), "2");
422422
}
423+
424+
TEST(MsgPackDocument, TestInputYAMLBoolean) {
425+
Document Doc;
426+
auto GetFirst = [](Document &Doc) { return Doc.getRoot().getArray()[0]; };
427+
auto ToYAML = [](Document &Doc) {
428+
std::string S;
429+
raw_string_ostream OS(S);
430+
Doc.toYAML(OS);
431+
return S;
432+
};
433+
434+
bool Ok;
435+
436+
Ok = Doc.fromYAML("- n\n");
437+
ASSERT_TRUE(Ok);
438+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::String);
439+
ASSERT_EQ(GetFirst(Doc).getString(), "n");
440+
ASSERT_EQ(ToYAML(Doc), "---\n- n\n...\n");
441+
442+
Ok = Doc.fromYAML("- y\n");
443+
ASSERT_TRUE(Ok);
444+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::String);
445+
ASSERT_EQ(GetFirst(Doc).getString(), "y");
446+
ASSERT_EQ(ToYAML(Doc), "---\n- y\n...\n");
447+
448+
Ok = Doc.fromYAML("- no\n");
449+
ASSERT_TRUE(Ok);
450+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::String);
451+
ASSERT_EQ(GetFirst(Doc).getString(), "no");
452+
ASSERT_EQ(ToYAML(Doc), "---\n- no\n...\n");
453+
454+
Ok = Doc.fromYAML("- yes\n");
455+
ASSERT_TRUE(Ok);
456+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::String);
457+
ASSERT_EQ(GetFirst(Doc).getString(), "yes");
458+
ASSERT_EQ(ToYAML(Doc), "---\n- yes\n...\n");
459+
460+
Ok = Doc.fromYAML("- false\n");
461+
ASSERT_TRUE(Ok);
462+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean);
463+
ASSERT_EQ(GetFirst(Doc).getBool(), false);
464+
ASSERT_EQ(ToYAML(Doc), "---\n- false\n...\n");
465+
466+
Ok = Doc.fromYAML("- true\n");
467+
ASSERT_TRUE(Ok);
468+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean);
469+
ASSERT_EQ(GetFirst(Doc).getBool(), true);
470+
ASSERT_EQ(ToYAML(Doc), "---\n- true\n...\n");
471+
472+
Ok = Doc.fromYAML("- !str false\n");
473+
ASSERT_TRUE(Ok);
474+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::String);
475+
ASSERT_EQ(GetFirst(Doc).getString(), "false");
476+
ASSERT_EQ(ToYAML(Doc), "---\n- !str 'false'\n...\n");
477+
478+
Ok = Doc.fromYAML("- !str true\n");
479+
ASSERT_TRUE(Ok);
480+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::String);
481+
ASSERT_EQ(GetFirst(Doc).getString(), "true");
482+
ASSERT_EQ(ToYAML(Doc), "---\n- !str 'true'\n...\n");
483+
484+
// FIXME: A fix for these requires changes in YAMLParser/YAMLTraits.
485+
Ok = Doc.fromYAML("- \"false\"\n");
486+
ASSERT_TRUE(Ok);
487+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean);
488+
ASSERT_EQ(GetFirst(Doc).getBool(), false);
489+
ASSERT_EQ(ToYAML(Doc), "---\n- false\n...\n");
490+
491+
Ok = Doc.fromYAML("- \"true\"\n");
492+
ASSERT_TRUE(Ok);
493+
ASSERT_EQ(GetFirst(Doc).getKind(), Type::Boolean);
494+
ASSERT_EQ(GetFirst(Doc).getBool(), true);
495+
ASSERT_EQ(ToYAML(Doc), "---\n- true\n...\n");
496+
}

0 commit comments

Comments
 (0)