2014-03-23 08:14:48 +04:00
|
|
|
#include <cassert>
|
|
|
|
|
|
2012-05-20 00:34:02 +04:00
|
|
|
#include "nodebuilder.h"
|
2014-03-23 08:14:48 +04:00
|
|
|
#include "yaml-cpp/node/detail/node.h"
|
2012-05-20 00:34:02 +04:00
|
|
|
#include "yaml-cpp/node/impl.h"
|
2014-03-23 08:14:48 +04:00
|
|
|
#include "yaml-cpp/node/node.h"
|
|
|
|
|
#include "yaml-cpp/node/type.h"
|
2012-05-20 00:34:02 +04:00
|
|
|
|
2014-03-22 22:05:03 +04:00
|
|
|
namespace YAML {
|
2014-03-23 08:14:48 +04:00
|
|
|
struct Mark;
|
|
|
|
|
|
2014-03-22 22:05:03 +04:00
|
|
|
NodeBuilder::NodeBuilder()
|
2019-03-14 01:18:34 +03:00
|
|
|
: m_pMemory(new detail::memory_holder),
|
|
|
|
|
m_pRoot(nullptr),
|
|
|
|
|
m_stack{},
|
|
|
|
|
m_anchors{},
|
|
|
|
|
m_keys{},
|
2023-11-04 11:22:05 +03:00
|
|
|
m_mergeDicts{},
|
2019-03-14 01:18:34 +03:00
|
|
|
m_mapDepth(0) {
|
2018-07-03 07:59:04 +03:00
|
|
|
m_anchors.push_back(nullptr); // since the anchors start at 1
|
2014-03-22 22:05:03 +04:00
|
|
|
}
|
|
|
|
|
|
2019-10-02 16:38:49 +03:00
|
|
|
NodeBuilder::~NodeBuilder() = default;
|
2014-03-22 22:05:03 +04:00
|
|
|
|
|
|
|
|
Node NodeBuilder::Root() {
|
|
|
|
|
if (!m_pRoot)
|
|
|
|
|
return Node();
|
|
|
|
|
|
|
|
|
|
return Node(*m_pRoot, m_pMemory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeBuilder::OnDocumentStart(const Mark&) {}
|
|
|
|
|
|
|
|
|
|
void NodeBuilder::OnDocumentEnd() {}
|
|
|
|
|
|
2015-03-31 14:23:02 +03:00
|
|
|
void NodeBuilder::OnNull(const Mark& mark, anchor_t anchor) {
|
|
|
|
|
detail::node& node = Push(mark, anchor);
|
2014-03-22 22:05:03 +04:00
|
|
|
node.set_null();
|
|
|
|
|
Pop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeBuilder::OnAlias(const Mark& /* mark */, anchor_t anchor) {
|
|
|
|
|
detail::node& node = *m_anchors[anchor];
|
|
|
|
|
Push(node);
|
|
|
|
|
Pop();
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-31 14:23:02 +03:00
|
|
|
void NodeBuilder::OnScalar(const Mark& mark, const std::string& tag,
|
2014-03-22 22:05:03 +04:00
|
|
|
anchor_t anchor, const std::string& value) {
|
2015-03-31 14:23:02 +03:00
|
|
|
detail::node& node = Push(mark, anchor);
|
2014-03-22 22:05:03 +04:00
|
|
|
node.set_scalar(value);
|
|
|
|
|
node.set_tag(tag);
|
|
|
|
|
Pop();
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-12 08:00:39 +03:00
|
|
|
void NodeBuilder::OnSequenceStart(const Mark& mark, const std::string& tag,
|
|
|
|
|
anchor_t anchor, EmitterStyle::value style) {
|
2015-03-31 14:23:02 +03:00
|
|
|
detail::node& node = Push(mark, anchor);
|
2014-03-22 22:05:03 +04:00
|
|
|
node.set_tag(tag);
|
|
|
|
|
node.set_type(NodeType::Sequence);
|
2015-01-24 22:11:43 +03:00
|
|
|
node.set_style(style);
|
2014-03-22 22:05:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeBuilder::OnSequenceEnd() { Pop(); }
|
|
|
|
|
|
2015-03-31 14:23:02 +03:00
|
|
|
void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag,
|
2015-01-24 21:26:16 +03:00
|
|
|
anchor_t anchor, EmitterStyle::value style) {
|
2015-03-31 14:23:02 +03:00
|
|
|
detail::node& node = Push(mark, anchor);
|
2014-03-22 22:05:03 +04:00
|
|
|
node.set_type(NodeType::Map);
|
|
|
|
|
node.set_tag(tag);
|
2015-01-24 22:11:43 +03:00
|
|
|
node.set_style(style);
|
2014-03-22 22:05:03 +04:00
|
|
|
m_mapDepth++;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-04 11:22:05 +03:00
|
|
|
void MergeMapCollection(detail::node& map_to, detail::node& map_from,
|
|
|
|
|
detail::shared_memory_holder& pMemory) {
|
|
|
|
|
const detail::node& const_map_to = map_to;
|
|
|
|
|
for (auto j = map_from.begin(); j != map_from.end(); j++) {
|
|
|
|
|
detail::node* s = const_map_to.get(*j->first, pMemory);
|
|
|
|
|
if (s == nullptr) {
|
|
|
|
|
map_to.insert(*j->first, *j->second, pMemory);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-22 22:05:03 +04:00
|
|
|
void NodeBuilder::OnMapEnd() {
|
|
|
|
|
assert(m_mapDepth > 0);
|
2023-11-04 11:22:05 +03:00
|
|
|
detail::node& collection = *m_stack.back();
|
|
|
|
|
for (detail::node* n : m_mergeDicts) {
|
|
|
|
|
MergeMapCollection(collection, *n, m_pMemory);
|
|
|
|
|
}
|
|
|
|
|
m_mergeDicts.clear();
|
2014-03-22 22:05:03 +04:00
|
|
|
m_mapDepth--;
|
|
|
|
|
Pop();
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-31 14:23:02 +03:00
|
|
|
detail::node& NodeBuilder::Push(const Mark& mark, anchor_t anchor) {
|
2014-03-22 22:05:03 +04:00
|
|
|
detail::node& node = m_pMemory->create_node();
|
2015-03-31 14:23:02 +03:00
|
|
|
node.set_mark(mark);
|
2014-03-22 22:05:03 +04:00
|
|
|
RegisterAnchor(anchor, node);
|
|
|
|
|
Push(node);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeBuilder::Push(detail::node& node) {
|
|
|
|
|
const bool needsKey =
|
|
|
|
|
(!m_stack.empty() && m_stack.back()->type() == NodeType::Map &&
|
|
|
|
|
m_keys.size() < m_mapDepth);
|
|
|
|
|
|
|
|
|
|
m_stack.push_back(&node);
|
|
|
|
|
if (needsKey)
|
2020-06-15 23:28:19 +03:00
|
|
|
m_keys.emplace_back(&node, false);
|
2014-03-22 22:05:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeBuilder::Pop() {
|
|
|
|
|
assert(!m_stack.empty());
|
|
|
|
|
if (m_stack.size() == 1) {
|
|
|
|
|
m_pRoot = m_stack[0];
|
|
|
|
|
m_stack.pop_back();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
detail::node& node = *m_stack.back();
|
|
|
|
|
m_stack.pop_back();
|
|
|
|
|
|
|
|
|
|
detail::node& collection = *m_stack.back();
|
|
|
|
|
if (collection.type() == NodeType::Sequence) {
|
|
|
|
|
collection.push_back(node, m_pMemory);
|
|
|
|
|
} else if (collection.type() == NodeType::Map) {
|
|
|
|
|
assert(!m_keys.empty());
|
|
|
|
|
PushedKey& key = m_keys.back();
|
|
|
|
|
if (key.second) {
|
2023-11-04 11:22:05 +03:00
|
|
|
detail::node& nk = *key.first;
|
|
|
|
|
if (nk.type() == NodeType::Scalar &&
|
|
|
|
|
((nk.tag() == "tag:yaml.org,2002:merge" && nk.scalar() == "<<") ||
|
|
|
|
|
(nk.tag() == "?" && nk.scalar() == "<<"))) {
|
|
|
|
|
if (node.type() == NodeType::Map) {
|
|
|
|
|
m_mergeDicts.emplace_back(&node);
|
|
|
|
|
m_keys.pop_back();
|
|
|
|
|
} else if (node.type() == NodeType::Sequence) {
|
|
|
|
|
for (auto i = node.begin(); i != node.end(); i++) {
|
|
|
|
|
auto v = *i;
|
|
|
|
|
if ((*v).type() == NodeType::Map) {
|
|
|
|
|
m_mergeDicts.emplace_back(&(*v));
|
|
|
|
|
} else {
|
|
|
|
|
throw ParserException(
|
|
|
|
|
node.mark(),
|
|
|
|
|
ErrorMsg::MERGE_KEY_NEEDS_SINGLE_OR_SEQUENCE_OF_MAPS);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_keys.pop_back();
|
|
|
|
|
} else {
|
|
|
|
|
throw ParserException(
|
|
|
|
|
node.mark(),
|
|
|
|
|
ErrorMsg::MERGE_KEY_NEEDS_SINGLE_OR_SEQUENCE_OF_MAPS);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
collection.insert(*key.first, node, m_pMemory);
|
|
|
|
|
m_keys.pop_back();
|
|
|
|
|
}
|
2014-03-22 22:05:03 +04:00
|
|
|
} else {
|
|
|
|
|
key.second = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
assert(false);
|
|
|
|
|
m_stack.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeBuilder::RegisterAnchor(anchor_t anchor, detail::node& node) {
|
|
|
|
|
if (anchor) {
|
|
|
|
|
assert(anchor == m_anchors.size());
|
|
|
|
|
m_anchors.push_back(&node);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-14 01:18:34 +03:00
|
|
|
} // namespace YAML
|