nodebuilder.cpp 2.86 KB
Newer Older
1
2
3
4
5
6
#include "nodebuilder.h"
#include "yaml-cpp/mark.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/impl.h"
#include <cassert>

Jesse Beder's avatar
Jesse Beder committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
namespace YAML {
NodeBuilder::NodeBuilder()
    : m_pMemory(new detail::memory_holder), m_pRoot(0), m_mapDepth(0) {
  m_anchors.push_back(0);  // since the anchors start at 1
}

NodeBuilder::~NodeBuilder() {}

Node NodeBuilder::Root() {
  if (!m_pRoot)
    return Node();

  return Node(*m_pRoot, m_pMemory);
}

void NodeBuilder::OnDocumentStart(const Mark&) {}

void NodeBuilder::OnDocumentEnd() {}

void NodeBuilder::OnNull(const Mark& /* mark */, anchor_t anchor) {
  detail::node& node = Push(anchor);
  node.set_null();
  Pop();
}

void NodeBuilder::OnAlias(const Mark& /* mark */, anchor_t anchor) {
  detail::node& node = *m_anchors[anchor];
  Push(node);
  Pop();
}

void NodeBuilder::OnScalar(const Mark& /* mark */, const std::string& tag,
                           anchor_t anchor, const std::string& value) {
  detail::node& node = Push(anchor);
  node.set_scalar(value);
  node.set_tag(tag);
  Pop();
}

void NodeBuilder::OnSequenceStart(const Mark& /* mark */,
                                  const std::string& tag, anchor_t anchor) {
  detail::node& node = Push(anchor);
  node.set_tag(tag);
  node.set_type(NodeType::Sequence);
}

void NodeBuilder::OnSequenceEnd() { Pop(); }

void NodeBuilder::OnMapStart(const Mark& /* mark */, const std::string& tag,
                             anchor_t anchor) {
  detail::node& node = Push(anchor);
  node.set_type(NodeType::Map);
  node.set_tag(tag);
  m_mapDepth++;
}

void NodeBuilder::OnMapEnd() {
  assert(m_mapDepth > 0);
  m_mapDepth--;
  Pop();
}

detail::node& NodeBuilder::Push(anchor_t anchor) {
  detail::node& node = m_pMemory->create_node();
  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)
    m_keys.push_back(PushedKey(&node, false));
}

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) {
      collection.insert(*key.first, node, m_pMemory);
      m_keys.pop_back();
    } 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);
  }
}
122
}