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