map.cpp 3.37 KB
Newer Older
1
2
#include "map.h"
#include "node.h"
3
4
#include "scanner.h"
#include "token.h"
Jesse Beder's avatar
Jesse Beder committed
5
#include "exceptions.h"
6
7
8
9
10
11
12
13

namespace YAML
{
	Map::Map()
	{
	}

	Map::~Map()
14
15
16
17
18
	{
		Clear();
	}

	void Map::Clear()
19
20
21
22
23
	{
		for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
			delete it->first;
			delete it->second;
		}
24
		m_data.clear();
25
	}
26

27
	bool Map::GetBegin(std::map <Node *, Node *>::const_iterator& it) const
28
29
30
31
32
	{
		it = m_data.begin();
		return true;
	}

33
	bool Map::GetEnd(std::map <Node *, Node *>::const_iterator& it) const
34
35
36
37
38
	{
		it = m_data.end();
		return true;
	}

39
	void Map::Parse(Scanner *pScanner, const ParserState& state)
40
	{
41
42
43
44
		Clear();

		// split based on start token
		Token *pToken = pScanner->PeekNextToken();
45
46

		switch(pToken->type) {
47
48
			case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break;
			case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break;
49
50
51
		}
	}

52
	void Map::ParseBlock(Scanner *pScanner, const ParserState& state)
53
	{
54
55
56
		// eat start token
		pScanner->EatNextToken();

57
58
59
		while(1) {
			Token *pToken = pScanner->PeekNextToken();
			if(!pToken)
Jesse Beder's avatar
Jesse Beder committed
60
				throw MapEndNotFound();
61
62

			if(pToken->type != TT_KEY && pToken->type != TT_BLOCK_END)
Jesse Beder's avatar
Jesse Beder committed
63
				throw MapEndNotFound();
64
65
66
67
68
69
70
71
72
73

			pScanner->PopNextToken();
			if(pToken->type == TT_BLOCK_END)
				break;

			Node *pKey = new Node;
			Node *pValue = new Node;
			m_data[pKey] = pValue;

			// grab key
74
			pKey->Parse(pScanner, state);
75
76
77
78

			// now grab value (optional)
			if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) {
				pScanner->PopNextToken();
79
				pValue->Parse(pScanner, state);
80
81
82
83
			}
		}
	}

84
	void Map::ParseFlow(Scanner *pScanner, const ParserState& state)
85
	{
86
87
88
		// eat start token
		pScanner->EatNextToken();

89
90
91
		while(1) {
			Token *pToken = pScanner->PeekNextToken();
			if(!pToken)
Jesse Beder's avatar
Jesse Beder committed
92
				throw MapEndNotFound();
93
94
95
96
97
98
99
100
101

			// first check for end
			if(pToken->type == TT_FLOW_MAP_END) {
				pScanner->EatNextToken();
				break;
			}

			// now it better be a key
			if(pToken->type != TT_KEY)
Jesse Beder's avatar
Jesse Beder committed
102
				throw MapEndNotFound();
103
104
105
106
107
108
109
110

			pScanner->PopNextToken();

			Node *pKey = new Node;
			Node *pValue = new Node;
			m_data[pKey] = pValue;

			// grab key
111
			pKey->Parse(pScanner, state);
112
113
114
115

			// now grab value (optional)
			if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) {
				pScanner->PopNextToken();
116
				pValue->Parse(pScanner, state);
117
118
119
120
121
122
123
			}

			// now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node)
			pToken = pScanner->PeekNextToken();
			if(pToken->type == TT_FLOW_ENTRY)
				pScanner->EatNextToken();
			else if(pToken->type != TT_FLOW_MAP_END)
Jesse Beder's avatar
Jesse Beder committed
124
				throw MapEndNotFound();
125
126
127
		}
	}

128
	void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
129
	{
130
131
		if(startedLine && !onlyOneCharOnLine)
			out << std::endl;
132
133

		for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
134
135
136
137
			if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) {
				for(int i=0;i<indent;i++)
					out << "  ";
			}
138

139
140
141
142
			out << "? ";
			it->first->Write(out, indent + 1, true, it!= m_data.begin() || !startedLine || onlyOneCharOnLine);

			for(int i=0;i<indent;i++)
143
				out << "  ";
144
145
			out << ": ";
			it->second->Write(out, indent + 1, true, true);
146
		}
147
148
149

		if(m_data.empty())
			out << std::endl;
150
	}
151
}