1 #include <cassert>
2
3 #include "nodebuilder.h"
4 #include "yaml-cpp/node/detail/node.h"
5 #include "yaml-cpp/node/impl.h"
6 #include "yaml-cpp/node/node.h"
7 #include "yaml-cpp/node/type.h"
8
9 namespace YAML {
10 struct Mark;
11
NodeBuilder()12 NodeBuilder::NodeBuilder()
13 : m_pMemory(new detail::memory_holder),
14 m_pRoot(nullptr),
15 m_stack{},
16 m_anchors{},
17 m_keys{},
18 m_mapDepth(0) {
19 m_anchors.push_back(nullptr); // since the anchors start at 1
20 }
21
22 NodeBuilder::~NodeBuilder() = default;
23
Root()24 Node NodeBuilder::Root() {
25 if (!m_pRoot)
26 return Node();
27
28 return Node(*m_pRoot, m_pMemory);
29 }
30
OnDocumentStart(const Mark &)31 void NodeBuilder::OnDocumentStart(const Mark&) {}
32
OnDocumentEnd()33 void NodeBuilder::OnDocumentEnd() {}
34
OnNull(const Mark & mark,anchor_t anchor)35 void NodeBuilder::OnNull(const Mark& mark, anchor_t anchor) {
36 detail::node& node = Push(mark, anchor);
37 node.set_null();
38 Pop();
39 }
40
OnAlias(const Mark &,anchor_t anchor)41 void NodeBuilder::OnAlias(const Mark& /* mark */, anchor_t anchor) {
42 detail::node& node = *m_anchors[anchor];
43 Push(node);
44 Pop();
45 }
46
OnScalar(const Mark & mark,const std::string & tag,anchor_t anchor,const std::string & value)47 void NodeBuilder::OnScalar(const Mark& mark, const std::string& tag,
48 anchor_t anchor, const std::string& value) {
49 detail::node& node = Push(mark, anchor);
50 node.set_scalar(value);
51 node.set_tag(tag);
52 Pop();
53 }
54
OnSequenceStart(const Mark & mark,const std::string & tag,anchor_t anchor,EmitterStyle::value style)55 void NodeBuilder::OnSequenceStart(const Mark& mark, const std::string& tag,
56 anchor_t anchor, EmitterStyle::value style) {
57 detail::node& node = Push(mark, anchor);
58 node.set_tag(tag);
59 node.set_type(NodeType::Sequence);
60 node.set_style(style);
61 }
62
OnSequenceEnd()63 void NodeBuilder::OnSequenceEnd() { Pop(); }
64
OnMapStart(const Mark & mark,const std::string & tag,anchor_t anchor,EmitterStyle::value style)65 void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag,
66 anchor_t anchor, EmitterStyle::value style) {
67 detail::node& node = Push(mark, anchor);
68 node.set_type(NodeType::Map);
69 node.set_tag(tag);
70 node.set_style(style);
71 m_mapDepth++;
72 }
73
OnMapEnd()74 void NodeBuilder::OnMapEnd() {
75 assert(m_mapDepth > 0);
76 m_mapDepth--;
77 Pop();
78 }
79
Push(const Mark & mark,anchor_t anchor)80 detail::node& NodeBuilder::Push(const Mark& mark, anchor_t anchor) {
81 detail::node& node = m_pMemory->create_node();
82 node.set_mark(mark);
83 RegisterAnchor(anchor, node);
84 Push(node);
85 return node;
86 }
87
Push(detail::node & node)88 void NodeBuilder::Push(detail::node& node) {
89 const bool needsKey =
90 (!m_stack.empty() && m_stack.back()->type() == NodeType::Map &&
91 m_keys.size() < m_mapDepth);
92
93 m_stack.push_back(&node);
94 if (needsKey)
95 m_keys.emplace_back(&node, false);
96 }
97
Pop()98 void NodeBuilder::Pop() {
99 assert(!m_stack.empty());
100 if (m_stack.size() == 1) {
101 m_pRoot = m_stack[0];
102 m_stack.pop_back();
103 return;
104 }
105
106 detail::node& node = *m_stack.back();
107 m_stack.pop_back();
108
109 detail::node& collection = *m_stack.back();
110
111 if (collection.type() == NodeType::Sequence) {
112 collection.push_back(node, m_pMemory);
113 } else if (collection.type() == NodeType::Map) {
114 assert(!m_keys.empty());
115 PushedKey& key = m_keys.back();
116 if (key.second) {
117 collection.insert(*key.first, node, m_pMemory);
118 m_keys.pop_back();
119 } else {
120 key.second = true;
121 }
122 } else {
123 assert(false);
124 m_stack.clear();
125 }
126 }
127
RegisterAnchor(anchor_t anchor,detail::node & node)128 void NodeBuilder::RegisterAnchor(anchor_t anchor, detail::node& node) {
129 if (anchor) {
130 assert(anchor == m_anchors.size());
131 m_anchors.push_back(&node);
132 }
133 }
134 } // namespace YAML
135