Fix merge-key handling in case the dictionary contains a sub-dictionary

This commit is contained in:
Nicolas Le Scouarnec 2023-12-08 20:42:30 +01:00
parent 6bbc603b22
commit 629297180d
3 changed files with 12 additions and 6 deletions

View File

@ -70,6 +70,7 @@ void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag,
node.set_tag(tag); node.set_tag(tag);
node.set_style(style); node.set_style(style);
m_mapDepth++; m_mapDepth++;
m_mergeDicts.emplace_back();
} }
void MergeMapCollection(detail::node& map_to, detail::node& map_from, void MergeMapCollection(detail::node& map_to, detail::node& map_from,
@ -86,11 +87,12 @@ void MergeMapCollection(detail::node& map_to, detail::node& map_from,
void NodeBuilder::OnMapEnd() { void NodeBuilder::OnMapEnd() {
assert(m_mapDepth > 0); assert(m_mapDepth > 0);
detail::node& collection = *m_stack.back(); detail::node& collection = *m_stack.back();
for (detail::node* n : m_mergeDicts) { auto& toMerge = *m_mergeDicts.rbegin();
for (detail::node* n : toMerge) {
MergeMapCollection(collection, *n, m_pMemory); MergeMapCollection(collection, *n, m_pMemory);
} }
m_mergeDicts.clear();
m_mapDepth--; m_mapDepth--;
m_mergeDicts.pop_back();
Pop(); Pop();
} }
@ -135,13 +137,13 @@ void NodeBuilder::Pop() {
((nk.tag() == "tag:yaml.org,2002:merge" && nk.scalar() == "<<") || ((nk.tag() == "tag:yaml.org,2002:merge" && nk.scalar() == "<<") ||
(nk.tag() == "?" && nk.scalar() == "<<"))) { (nk.tag() == "?" && nk.scalar() == "<<"))) {
if (node.type() == NodeType::Map) { if (node.type() == NodeType::Map) {
m_mergeDicts.emplace_back(&node); m_mergeDicts.rbegin()->emplace_back(&node);
m_keys.pop_back(); m_keys.pop_back();
} else if (node.type() == NodeType::Sequence) { } else if (node.type() == NodeType::Sequence) {
for (auto i = node.begin(); i != node.end(); i++) { for (auto i = node.begin(); i != node.end(); i++) {
auto v = *i; auto v = *i;
if ((*v).type() == NodeType::Map) { if ((*v).type() == NodeType::Map) {
m_mergeDicts.emplace_back(&(*v)); m_mergeDicts.rbegin()->emplace_back(&(*v));
} else { } else {
throw ParserException( throw ParserException(
node.mark(), node.mark(),

View File

@ -67,7 +67,7 @@ class NodeBuilder : public EventHandler {
using PushedKey = std::pair<detail::node*, bool>; using PushedKey = std::pair<detail::node*, bool>;
std::vector<PushedKey> m_keys; std::vector<PushedKey> m_keys;
Nodes m_mergeDicts; std::vector<Nodes> m_mergeDicts;
std::size_t m_mapDepth; std::size_t m_mapDepth;
}; };
} // namespace YAML } // namespace YAML

View File

@ -188,7 +188,7 @@ TEST(LoadNodeTest, MergeKeyB) {
Node node = Load( Node node = Load(
"{x: &foo {a : 1,b : 1,c : 1}, y: &bar {d: 2, e : 2, f : 2, a : 2}, z: " "{x: &foo {a : 1,b : 1,c : 1}, y: &bar {d: 2, e : 2, f : 2, a : 2}, z: "
"&stuff { << : *foo, b : 3}, w: { << : [*stuff, *bar], c: 4 }, v: { '<<' " "&stuff { << : *foo, b : 3}, w: { << : [*stuff, *bar], c: 4 }, v: { '<<' "
": *foo } , u : {!!merge << : *bar} }"); ": *foo } , u : {!!merge << : *bar}, t: {!!merge << : *bar, h: 3} }");
EXPECT_EQ(NodeType::Map, node["z"].Type()); EXPECT_EQ(NodeType::Map, node["z"].Type());
EXPECT_EQ(NodeType::Map, node["w"].Type()); EXPECT_EQ(NodeType::Map, node["w"].Type());
EXPECT_FALSE(node["z"]["<<"]); EXPECT_FALSE(node["z"]["<<"]);
@ -208,6 +208,10 @@ TEST(LoadNodeTest, MergeKeyB) {
EXPECT_FALSE(node["u"]["<<"]); EXPECT_FALSE(node["u"]["<<"]);
EXPECT_EQ(2, node["u"]["d"].as<int>()); EXPECT_EQ(2, node["u"]["d"].as<int>());
EXPECT_FALSE(node["t"]["<<"]);
EXPECT_EQ(2, node["t"]["d"].as<int>());
EXPECT_EQ(3, node["t"]["h"].as<int>());
} }
TEST(LoadNodeTest, ForceInsertIntoMap) { TEST(LoadNodeTest, ForceInsertIntoMap) {