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